认知 android.app.SearchManager(一)

Android

Android

在看到《Interducing Quick Search Box for Android》一文之前,我从没有想到过把应用和系统搜索服务联系起来。看过 Android-developers 的博文之后,惊讶原来 Android 提供了这么好的搜索机制,于是立即打开 SearchManager 的文档来补回这一课。文档共分了9个部分来介绍,在这里我也按图索骥,一步一步来认知它,所以会采用一个博文系列的形式来记录我的认知过程。

SearchManager 的作用是提供对系统搜索服务的访问。要获取到对 Search Manager 的直接访问,只有通过 context.getSystemService(Context.SEARCH_SERVICE),而试图通过初始化 SearchManager,则是行不通的。

从搜索的角度来看,应用可分为三类: unsearchable 类型应用、Query-Search 类型应用和 Filter-Search 类型应用。大部分应用是属于后两种。不过,即便是第一种类型,应用也仍旧支持对搜索的调用。后两种的区分就在于,Query-Search 类型应用执行 batch-mode 搜索,每一个查询字符串都被转化成结果列表;Filter-Search 类型应用则提供 filter-as-you-type 搜索。通常来讲,对基于网络的数据进行 Query Search,而对本地数据,则需要 Filter Search。

除非万不得已,所有的应用都要支持调出搜索界面。换言之,当用户执行了搜索命令以后,搜索界面就要呈现给用户。目前,搜索命令通常是定义在菜单栏中名为“Search”的选项,在一些手机上会是一个特定的搜索键。

万一,应用属于第一种类型,你还是可以在 web search 模式下调出搜索界面。按下“搜索”以后,浏览器就会打开。这里需要注意,搜索界面是以浮动窗口(floating window)的形式出现,对 activity stack 是不会有任何改变的。

开发者应该考虑清楚采用什么样的方式来处理搜索请求,以下是四种建议:

  1. 自行捕获搜索命令,包括搜索按钮和菜单项,直接调用搜索界面。
  2. 提供 type-to-search,用户输入任何字符的同时自动启用搜索。
  3. 万一应用是 unsearchable,则允许通过搜索键(或者搜索菜单性)进行全局搜索。
  4. 彻底禁用搜索。

如果使用第一种建议,在定义菜单项的时候,Andriod 已经默认提供了一些资源,开发者可以使用 android.R.drawable.ic_search_category_default 作为菜单项的 icon,同时使用 SearchManager.MENU_KEY 作为快捷键。然后调用 onSearchRequested() 。

如果使用第二种建议,则需要在Activity里,调用setDefaultKeyMode,如下所示:

// search within your activity
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
// search using platform global search
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL);

如果使用第三种建议,也就是使用 Quick Search Box 进行对设备和网络的搜索,有两种方式可供选择。其一,在 application 或 activity 中定义“search”,也就是在 mainifest 中增加一个meta-data;其二,通过默认实现 onSearchRequest() 触发全局搜索(也可以通过startSearth(String, boolean, Bundle, boolean))

如果使用第四种建议,则要覆写 onSearchRequest() 方法,如下所示:

@Override
public boolean onSearchRequested() {
    return false;
}

当搜索界面出现,原来的 activity 就会失去输入焦点,当搜索结束时,会有三种可能的结果:首先,用户取消了搜索界面,原来的 activity 重新获得输入焦点。可以通过 setOnDismissListener(SearchManager.OnDismissListener) 和 setOnCancelListener(SearchManager.OnCancelListener) 来获取清除搜索界面的事件通知。

其次,如果用户执行了搜索,这就需要切换到另外一个 activity 来接收和处理search Intent,原来的 activity 就可能进入 pause 或者 stop 状态。

最后,如果用户执行了搜索,并且当前的 activity 就是 search Intent 的接收者,则需要通过 onNewIntent 方法来接收消息。

4 Comments

mery18 11 月, 2009 at 2:36 下午

SearchManager searchManager = (SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);
这样不是就初始化了吗?

allankliu8 12 月, 2009 at 9:47 下午

这是SDK的一部分,其余部分您在翻译么?

我在观察Google Map中的Search,其中Search按钮是调用Google的Geocoder服务的。但是我并没有看到有另外一个View出现。好像这个应用中Invoker和Searchable是同一个Activity,将获得的Geocoder结果直接应用在地图中,或者利用toast弹出失败通知。是不是?而SDK中队Query Search主张两个Activity对应两个View。

我在做一个国内的Wifi本地地图,想尽可能地参考Gmap设计。只是应用不同的本地图层API而已。目前SearchManager还没有做出来。正在看这方面的说明。

Xu Haojie8 12 月, 2009 at 11:23 下午

由于一些原因,暂时中断了其余部分的翻译整理。— 我本意是想以自己的理解来阐述,但因为对这个方面的了解还不算深入,因此就成了“英译汉”,希望能帮到你。

allankliu9 12 月, 2009 at 1:14 下午

Google=search。无怪乎谷歌把个SearchManager做的那么复杂。昨天我看了SDK中的这部分。坦率地说,它写的有些复杂了。其实,基本上就是两种情况而已:a) web based query search b) local filter search。而所有的Manifest + searchable.xml,以及各类回调函数都是提供给框架使用的。SDK中关于关闭和使能 Web Browser based Search 其实没有特别的意义。混在一起说,让人云里雾里的。

搞了半天,最后我还是把自己的代码和APIDemo和Dr.TYT的BigPlanet的源代码做了比较,才发现最终问题出在了Manifest中的Meta-data声明出错。

Anyway,我总算在MapView中调出 Search UI了。接下来就是通过后台 ListActivity 去抓 Google Geocoder。

顺便说一下,您的翻译是我检索到的少数论及 SearchManager 的中文博客。非常感谢此文给我的方向指引。我原来想用半透背景+Form去模拟一个SearchBar出来。

Leave a comment

Your comment