目录

Android-细说searchView

目录

Android 细说searchView

请细读文章后半部分,结合实例,亲笔写的总结。

Android为程序的搜索功能提供了统一的搜索接口,searchdialog和search widget。

searchdialog只能为于activity 窗口的上方 ,search widget可以位于 任何位置 。

searchdialog和searchwidget的 其他

性 如下:

A

音搜索。

B

:根据最近的搜索

果,

出搜索建

C

:根据我

程序的

实际

搜索

果,

出搜索建

注1 :search widget在Android 3.0或更高版本才可用

searchdialog和search widget的搜索功能特性都一样,但是他们还有微小 区别 :

A,search dialog

是一

被系

控制的UI

件。但他被用

激活的

候,

它总

是出

在activity 的上方。

B,Android

统负责处

理search dialog 上所有的事件, 当

提交了

查询

,系

统会

这个查询请

传输

到我

的searchable activity , 让

searchable activity

正的

查询

。C,search widget 是SearchView的一 个实

例,

可以把

放在

的布局的任何地方。

D,

的,search widget 和一 个标

准的EditText widget 一 样

,不能做任何事情。但是

可以配置

android

统处

理所有的按

事件,把

查询请

传输给

合适的activity, 可以配置 它让它

像search dialog 一 样

提供search suggestions 。

E,search widget

在 Android 3.0 或更高版本才可用.search dialog 没

有此

限制

当用户在

search dialog

search widget

中执行一个搜索的时候,系统会创建一个

Intent

,并把查询关键字保存在里面,

然后启动我们在

AndroidManifest.xml

中声明好的

searchable activity

,并把

Intent

传送给它。

实现一个可以搜索的程序,主要需要以下几个部份 :

(1) search dialog or widget

配置文件 。

配置一个

XML

文件用于配置

search dialog

widget

的设置。对于

search dialog

,该配置文件的名字一般约定为

searchable.xml

(2) searchable activity 。

searchable activity

用于接收搜索关键字,并进行数据搜索和显示搜索结果。

(3) 搜索条。

search dialog

search widget

  • The search dialog

默认

search dialog

是隐藏。当我们按下了

SEARCH

键或在程序中调用

on SearchRequested()

,它将出现在屏幕的上方。

  • SearchView widget

使用

search widget

的时候,你可以把该搜索框放在我们

activity

的任何地方

,

通常把它作为

Act ion Bar

的一个菜单而不是放到

Layout

xml

里面,对于用户来说会显得更加方便。

具体实现步骤( 以

SDK

自带的

Sample  SearchableDictionary

工程分析举例 ):

(1)   创建配置文件searchable.xml,存放于res/xml文件夹下

<searchable xmlns:android

android:label= "@string/search_label”

android:hint= "@string/search_hint"

android:searchSettingsDescription= "@string/settings_description"

//搜索功能描述 android:searchSuggestAuthority

“com.example.android.searchabledict.DictionaryProvider” // Content Provider 的主机名, 它必须和你的content provider 的mainfest中的               android:authorities一致

android:searchSuggestIntentAction= “android.intent.act ion.VIEW”

//可选项,定义当用户选择了suggestion后发送给activity的Intent的Act ion,默认为Intent. ACT ION_SEARCH

android:searchSuggestIntentData= “content://com.example.android.searchabledict.DictionaryProvider/dictionary”

//定义当用户选择了suggestion后的发送给activity的intent的da ta,比如:

“content://com.example.android.searchabledict.DictionaryProvider/dictionary/1”(abbey这个单词的Uri)

android:searchSuggestSelection= " ?"

// 它就作为 selection参数传入到你的suggetion content provider的query函数中,固定为空格 +?

android:searchSuggestThreshold= “1”

android:includeInGlobalSearch= “true”

  //是否支持全局搜索,就是从桌面搜索

关于

searchable.xml

更多内容请参考

(

官方英文文档

)

(

中文翻译

)

(2)   创建SearchableActivity

searchable activity根据搜索关键字进行搜索,并显示搜索结果

1). MENIFEST.XML

声明

searchable activity

<activity

android:name

".SearchableDictionary"

android:launchMode

“singleInstance”

<act ion android:name

“android.intent.act ion.MAIN”

/>

<category android:name

“android.intent.category.LAUNCHER”

/>

<act ionandroid:name= “android.intent.act ion.SEARCH” />

<meta-da ta

android:name= “android.app.searchable”

android:resource= "@xml/searchable" />

<meta-da ta

android:name

" android.app.default_searchable “

android:value

".SearchableDictionary”

/>

//可有可无,这个主要是想让app的任何地方都可以实施搜索并向该activity发送Intent

创建

Searchable Activity

SearchableDictionary.java:

它重写了on NewIntent方法来处理新的Intent,如果这个activity是由我们手动点击应用图标启动的,Intent的act ion为Intent.ACT ION_MAIN,不会执行handleIntent里面的处理搜索的代码。另一方面它在菜单里又定义了一个搜索按钮作为actionbar的一部分显示在屏幕顶端了。当我们点击这个按钮时,通过直接调用on SearchRequested();就会在屏幕顶端出现一个在搜索框(Search Dialog),向里面输入英文单词(注意:会有suggestions下拉列表,后面再说它的配置),当你点击了其中一条或者按下了软键盘的右下角的“开始“键,就会立即给 SearchableDictionary这个 SearchableActivity发送一个Intent,其act ion根据你刚才的操作(是点了suggestion还是按了“开始”键)分别为:Intent.ACT ION_VIEW和Intent.ACT ION_SEARCH,其中这个IntentIntent.ACT ION_VIEW是在searchable.xml里面自主定义的。接着触发on NewIntent方法。

若是单击suggestion来的,那么intent.getData()可以获取这个suggestion的唯一Uri(比如:

“content://com.example.android.searchabledict.DictionaryProvider/dictionary/1”),然后启动WordActivity查询数据库并显示word这个单词的释义;若是按了“开始”键来的,那么intent.getStringExtra(SearchManager.QUERY);可以获取此次要搜索的关键词,然后通过showResults方法搜索数据库并显示搜索结果,可能不止一条结果,所以开头定义了一个ListView。

(3

)创建ContentProvider

?

MENIFEST.XML

里面声明:

<provider

android:name

".DictionaryProvider"

android:authorities= “com.example.android.searchabledict.DictionaryProvider”

/>

?       实现ContentProvider实现Suggestions

DictionaryProvider.java:

里面主要是public Cursor query(…)这个方法,提供显示搜索建议的Cursor,之前里面定义了一个UriMatcher,用于匹配识别搜索类型,当URI匹配时返回相应的匹配码:就是指当搜索框自动访问ContentProvider获取搜索建议时,URI是

“content://com.example.android.searchabledict.DictionaryProvider/search_suggest_query?limit=50” ,正好匹配 AUTHORITY + SearchManager.SUGGEST_URI_PATH_SHORTCUT ,返回匹配码 SEARCH_SUGGEST ,通过getSuggestions(selectionArgs[0])返回suggestions的cursor.当我们点击suggestions的任意一条后,search dialog消失并会向activity发送Intent,此时这个Intent包含了一条这条suggestion的uri,(比如 “content://com.example.android.searchabledict.DictionaryProvider/dictionary/1 ”)那么activity可以通过这个uri访问ContentProvider来获取cursor并显示结果,因此当UriMatcher匹配到这个uri时返回匹配码 GET_WORD ,通过调用getWord(uri)获取cursor。

当我们没有点击所给的suggestion而是点击了”开始”键强行搜索时,uri会是

“content://com.example.android.searchabledict.DictionaryProvider/dictionary ”,则返回匹配码 SEARCH_WORDS ,通过search(selectionArgs[0])搜索数据库并返回cursor。

匹配码 REFRESH_SHORTCUT 目前还用不到。

最后说明搜索框获得suggestions的cursor后,如何知道显示那些列的内容,

SearchManager 定义了两个固定列名: SearchManager.SUGGEST_COLUMN_TEXT_1 和 SearchManager.SUGGEST_COLUMN_TEXT_2 ,显示suggestions是就是取这两列的内容显示,矛盾的是我们的cursor对应的数据库表的列名几乎不可能都采用这两个固定的列名,解决办法是将查询到的结果表的列名重新命名为这两个固定列名。因此可以在DictionaryDatabase.java中看到定义了一个HashMap,用于映射原列名和改后的列名,这个HashMap应用于SQLiteQueryBuilder对象,就可以完成查询后结果表的列的重命名工作。

前面说过一个URI:

content://com.example.android.searchabledict.DictionaryProvider/dictionary/1

他是怎么来的?由于前面一部分来自searchable.xml里面的定义 android:searchSuggestIntentData

, 最后的1是id值,那么这个id值它是怎么获得的呢?你以为是取 _id这列的值吗,我们通常android里面数据库的主键通常用_id,但这不是必须的,要能获得id值,android在SearchManager又定义了一个列名:

SearchManager.SUGGEST_COLUMN_INTENT_DA TA_ID 用来获取id这个值,看它的名字就因该知道它是作为Intent的da ta的uri最后的id了。因此一般还需要在HashMap映射_id为 SearchManager.SUGGEST_COLUMN_INTENT_DA TA_ID

附 :android系统内置的ContentResolver 查询数据库并重命名列的方法(关键在projection):

Cursor cursor = resolver .query( uri , new String[] {

MediaStore.Audio.Media. _ID

  • " AS _id",

MediaStore.Audio.Media. _ID

  • " AS suggest_intent_da ta_id",

MediaStore.Audio.Media. TITLE

  • " AS suggest_text_1",

MediaStore.Audio.Media. ARTIST

  • " AS suggest_text_2" },

“title like’%” + keywd + “%’  or artist like ‘%” + keywd

+"%’ “, null , null );