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 );