zoukankan      html  css  js  c++  java
  • 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>

  • 相关阅读:
    LeetCode题解 | [简单-数组] 485.最大连续1的个数
    PAT乙级真题 | 1032 挖掘机技术哪家强
    [leetcode]两个列表的最小索引总和
    【leetCode】两个数组的交集
    手写hashMap(非红黑树)
    Redis 删除数据后不能自动释放内存的问题
    Spring @Async/@Transactional 失效的原因及解决方案
    完全平方数问题
    用队列实现栈
    memcached安装踩坑
  • 原文地址:https://www.cnblogs.com/douzhanshen/p/Quicksearchbox.html
Copyright © 2011-2022 走看看