QuickSearchBox

(1)framework层搜索管理器(SearchManager):主要功能是对Android系统全局搜索提供支持,当Android系统启动完成后会发出系统启动完成(BOOT_COMPLETED)广播,SearchManager接收到此广播后会通过PackageManager搜索系统中支持全局搜索的应用程序,SearchManager解析搜索源的配置信息并将这些配置信息封装成对象保存在List列表中供全局搜索应用程序使用。

(2)全局搜索AppWidget:AppWidget是搜索的入口,当用户需要使用全局搜索时会单击已经添加到桌面的全局搜索AppWidget,这时会打开全局搜索应用。

(3)全局搜索应用程序(QuickSearchBox):主要职能是接受用户的输入请求,启动异步搜索,将搜索到的结果显示。

(4)支持全局搜索的应用程序:每一个支持全局搜索的应用程序都需要实现一个ContentProvider,通过这个ContentProvider向外提供数据,全局搜索应用(QuickSearchBox)会调用这些ContentProvider获取数据。

系统启动后,在system_process进程中,会启动SearchManagerService服务(SearchManagerSerive.java),在初始化函数中针对Intent.ACTION_BOOT_COMPLETED注册了一个BroadcastReceiver,其run()函数中调用getSearchables()函数建立手机可搜索资源,Searchables的类函数buildSearchableList为真正建立搜索列表资源函数。

Searchables.java文件buildSearchableList()函数,跟踪searchList的创建。

final Intent intent = new Intent(Intent.ACTION_SEARCH);

searchList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);

queryIntentActivities的实现函数见PackageManagerService.java文件,

esolveInfo info = (ii < search_count) ? searchList.get(ii)

              : webSearchInfoList.get(ii - search_count);

ActivityInfo ai = info.activityInfo;

if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {

     SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);

     if (searchable != null) {

         newSearchablesList.add(searchable);

             newSearchablesMap.put(searchable.getSearchActivity(), searchable);

}

}

SearchableInfo类函数getActivityMetaData(),从代码中可以看到先loadXmlMetaData()加载xml文件,然后getActivityMetaData()获得searchable。

XmlResourceParser xml =

activityInfo.loadXmlMetaData(context.getPackageManager(), MD_LABEL_SEARCHABLE);

SearchableInfo searchable = getActivityMetaData(context, xml, cName);

getActivityMetaData()的关键语句:

result = new SearchableInfo(activityContext, attr, cName);

可以看出从xml文件中获得了SearchableInfo各成员变量。

TypedArray a = activityContext.obtainStyledAttributes(attr,

                   com.android.internal.R.styleable.Searchable);

mSearchMode= a.getInt(com.android.internal.R.styleable.Searchable_searchMode, 0);

mSuggestThreshold=a.getInt(com.android.internal.R.styleable.

Searchable_searchSuggestThreshold, 0);

ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority, 0);

if (pi != null) {

            suggestProviderPackage = pi.packageName;

     }

上述提到的xml文件为相应应用的/res/xml/searchable.xml

当用户在搜索栏中输入内容时,触发mQueryTextView的SearchTextWatcher()的listener函数运行,函数调用updateSuggestionsBuffered()。在函数updateSuggestionsBuffered()里,将runnable变量mUpdateSuggestionsTask加入到message queue,并延迟100ms运行。在runnable的run中调用updateSuggestions(),后者的重要执行语句:

Suggestions suggestions = getSuggestionsProvider().getSuggestions(

                query, mCorpus, getMaxSuggestions());

该语句的前一部分getSuggestionsProvider()获得SuggestionsProvider变量,由于SuggestionsProvider为虚类,其实现类SuggestionsProviderImpl,所以语句后半部分运行的是SuggestionsProviderImpl.java里的getSuggestions()函数。

    getSuggestions()有两个部分,第一部分根据query(查询内容)获得可搜索源列表,实现函数getCorporaToQuery();第二部分给每个搜索源创建一个QueryTask(本质为runnable)。函数getCorporaToQuery(),

     orderedCorpora = mCorpusRanker.getRankedCorpora();系统中所有可搜索源列表

corporaToQuery函数返回值,基于query,根据判断条件,得到的相应缩小到搜索源列表,shouldQueryCorpus()为判断函数,

if (query.length() == 0 && !corpus.isWebCorpus()) { return false; }

if (query.length() >= corpus.getQueryThreshold()) {

if (!corpus.queryAfterZeroResults() && mEmptyCorpora.containsKey(corpus)) {

           return false;

    }

    return true;

 }

返回true表示将此搜索源添加到corporaToQuery中,反之则不添加。corpus.getQueryThreshold()为开始搜索的query起始长度。

第二部分,QueryTask的startQueries()函数中,给每个corpus创建QueryTask。

for (SuggestionCursorProvider<C> provider : providers) {

QueryTask<C> task = new QueryTask<C>(query, maxResultsPerProvider, provider, handler,consumer, onlyOneProvider);

                executor.execute(task);

     }

之后,搜索会在QueryTask的run()函数中运行。

final C cursor = mProvider.getSuggestions(mQuery, mQueryLimit, mTheOnlyOne);// QueryTask.java

public CorpusResult getSuggestions(String query, int queryLimit, boolean onlyCorpus);//MultiSourceCorpus.java

private static Cursor getSuggestions(Context context, SearchableInfo searchable,

String query,int queryLimit);// SearchableSource.java

context.getContentResolver().query(uri, null, selection, selArgs, null);// 真正搜索db

applications、contacts、music三个搜索源在各自应用中的搜索入口:

ApplicationsProvider.java query()函数case SEARCH_SUGGEST

ContactsProvider2.java query()函数case SEARCH_SUGGESTIONS

MediaProvider.java query()函数 case AUDIO_SEARCH_BASIC

如果想让某个应用程序支持全局搜索,必须对这个应用程序进行一系列配置,并实现可被外界访问的内容提供者向搜索应用程序(QuickSearchBox)提供搜索结果,根据配置信息,应用程序可被搜索框架识别为搜索源,搜索应用程序(QuickSearchBox)也可以通过解析配置信息组拼成URI请求应用的ContentProvider获取搜索结果。

配置实现:

1. 应用程序中应当存在一个Activity,这个Activity在AndroidManifest.xml中的基本配置,如下:

        <activity android:name="SearchResultsActivity"

            android:theme="@style/TallTitleBarTheme"

            android:label="@string/contactsList"

            android:excludeFromRecents="true"

        >         

<intent-filter>

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

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

         </intent-filter>

<meta-data android:name="android.app.searchable"

              android:resource="@xml/searchable"

          />

        </activity>

Activity的作用:

第一,这样一个Activity在应用程序中是必须存在的,因为配置了上面代码后,这个Activity可以被识别为搜索源, 应用就支持全局搜索了。

第二,当搜索出结果信息后单击某一个结果项后会打开这个Activity显示搜索出的内容。

2. searchable.xml配置:

     <searchable xmlns:android="http://schemas.android.com/apk/res/android"

android:icon="@drawable/ic_tab_contacts"

    android:label="@string/contactsList"

    android:hint="@string/searchHint"

    android:searchMode="queryRewriteFromText"

    android:includeInGlobalSearch="true"

    android:searchSuggestAuthority="com.android.contacts"

    android:searchSuggestIntentAction="android.provider.Contacts.SEARCH_SUGGESTION_CLICKED"

    android:searchSuggestIntentData="content://com.android.contacts/contacts/lookup"

    android:searchSettingsDescription="@string/search_settings_description"

    <actionkey

        android:keycode="KEYCODE_CALL"

        android:queryActionMsg="call"

        android:suggestActionMsg="call"

    />

</searchable>

posted @ 2013-07-30 19:39  奥斯卡影帝  阅读(696)  评论(0编辑  收藏  举报