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 activitysearchable 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 dialogsearch 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键或在程序中调用onSearchRequested(),它将出现在屏幕的上方。

* SearchView widget使用search widget的时候,你可以把该搜索框放在我们activity的任何地方,通常把它作为Action Bar的一个菜单而不是放到Layoutxml里面,对于用户来说会显得更加方便。

 

具体实现步骤(SDK自带的Sample  SearchableDictionary工程分析举例):

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

<searchable xmlns:android="http://schemas.android.com/apk/res/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.action.VIEW"  

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

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

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

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

android:searchSuggestSelection=" ?"

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

android:searchSuggestThreshold="1"

android:includeInGlobalSearch="true">  //是否支持全局搜索,就是从桌面搜索

</searchable>

关于searchable.xml更多内容请参考(官方英文文档)

http://developer.android.com/guide/topics/search/searchable-config.html

(中文翻译)

http://hubingforever.blog.163.com/blog/static/171040579201142911524541/

 

(2)   创建SearchableActivity

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

1). MENIFEST.XML声明searchable activity

<activity

   android:name=".SearchableDictionary"

   android:launchMode="singleInstance" >

      <intent-filter>

        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER" />

      </intent-filter>

      <intent-filter>

         <actionandroid:name="android.intent.action.SEARCH" />

       </intent-filter>

      <meta-data

          android:name="android.app.searchable"

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

</activity>

<meta-data

     android:name="android.app.default_searchable"

      android:value=".SearchableDictionary" />

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

2) 创建Searchable Activity

SearchableDictionary.java:

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

若是单击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_1SearchManager.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_DATA_ID用来获取id这个值,看它的名字就因该知道它是作为Intent的data的uri最后的id了。因此一般还需要在HashMap映射_id为SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID

 

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

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

           MediaStore.Audio.Media._ID + " AS _id",

           MediaStore.Audio.Media._ID+ " AS suggest_intent_data_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);

你可能感兴趣的:(Android 细说searchView)