`
willsunforjava
  • 浏览: 167839 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android内核学习——SearchManager分析

 
阅读更多

1. 前言

Android系统提供了的一种搜索服务,利用此服务可以实现对系统中的应用、联系人、SMS等进行搜索,也提供转入浏览器中的搜索。Android Develop Blog中有一篇文章赞美了Android搜索功能的强大快捷——《Introducing Quick Search Box for Android》

SearchManager是搜索服务的入口,可以通过context.getSystemService(Context.SEARCH_SERVICE)获取SearchManager对象。SearchManager像其他ActivityManager、PackageManager等服务一样,是随系统启动一起启动的服务,并且启动后向ServiceManager注册自己,客户端最终获取搜索服务的途径也是通过binder机制向ServiceManager获取的。

从搜索的角度来看,应用可分为三类: unsearchable 类型应用、Query-Search 类型应用和 Filter-Search 类型应用。大部分应用是属于后两种。不过,即便是第一种类型,应用也仍旧支持对搜索的调用。后两种的区分就在于,Query-Search 类型应用执行 batch-mode 搜索,每一个查询字符串都被转化成结果列表;Filter-Search 类型应用则提供 filter-as-you-type 搜索。通常来讲,对基于网络的数据进行 Query Search,而对本地数据,则需要 Filter Search。

 

2. 整体类图

 


从上面的类图可以看出SearchManager提供的搜索服务最终是由ISearchManager这个接口的实现类提供的。同时SearchManager又实现了Dialog相关的两个接口OnDismissListener和OnCancelListener,以及内置一个SearchDialog,这些是为了搜索框实现服务的,因为在Android系统中的搜索服务界面就是一个Quick Search Box。下面我们就来先分析一个ISearchManager这一块提供了什么样的搜索服务以及如何提供搜索服务。

 

3.  SearchManagerService 提供搜索服务

ISearchManager是利用AIDL定义的,因此它的代码利用aapt编译生成的,组织方式使用了代理模式。ISearchManager.Stub的实现类是SearchManagerService,所以真正提供搜索服务的是这个类。

ISearchManager接口中定义搜索相关的基础服务,有如下的方法:

  • public SearchableInfo getSearchableInfo(ComponentName launchActivity) throws RemoteException;
  • public List<SearchableInfo> getSearchablesInGlobalSearch() throws RemoteException;
  • public ComponentName getGlobalSearchActivity() throws RemoteException;
  • public ComponentName getWebSearchActivity() throws RemoteException;
这些方法的实现都在SearchManagerService中,我们到这个类中看看这四个方法都提供什么样的功能。
SearchManagerService类中有个Searchables类型的属性mSearchables,它会在getSearchables方法使用的时候进行初始化。
    // This field is initialized lazily in getSearchables(), and then never modified.
    private Searchables mSearchables;
    private synchronized Searchables getSearchables() {
        if (mSearchables == null) {
            Log.i(TAG, "Building list of searchable activities");
            new MyPackageMonitor().register(mContext, true);
            mSearchables = new Searchables(mContext);
            mSearchables.buildSearchableList();
        }
        return mSearchables;
    }
 mSearchables这个对象记录了系统中可以被搜索到的组件的信息,SearchManagerService的四个方法的实现都是来自于mSearchables这对象。通过代码注释可以看到,这个对象在延迟初始化之后就不会再修改,其实这个对象还是会修改的,在mSearchables初始化时,会向MyPackageMonitor进行注册,这个类的功能就是当有程序添加进系统或者被删除时,mSearchables会刷新它里面的信息。
    class MyPackageMonitor extends PackageMonitor {
        @Override
        public void onSomePackagesChanged() {
            // Update list of searchable activities
            getSearchables().buildSearchableList();
            // Inform all listeners that the list of searchables has been updated.
            Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            mContext.sendBroadcast(intent);
        }
    }
 mSearchables里面信息的填充,是调用了buildSearchableList()方法,下面我们深入到Searchables中,看看它是如何获取“被搜索”组件的信息的。
Searchables内有五个属性来保存“被搜索”组件信息的,它们都是在buildSearchableList()方法中被实例化的。
    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
    private ArrayList<SearchableInfo> mSearchablesList = null;
    private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
    private ComponentName mGlobalSearchActivity = null;
    private ComponentName mWebSearchActivity = null;
在buildSearchableList方法中,我们可以看到,通过PackageManager的queryIntentActivities方法获取到了ACTION_SEARCH和ACTION_WEB_SEARCH的组件。
       final PackageManager pm = mContext.getPackageManager();

        // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
        List<ResolveInfo> searchList;
        final Intent intent = new Intent(Intent.ACTION_SEARCH);
        searchList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);

        List<ResolveInfo> webSearchInfoList;
        final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
        webSearchInfoList = pm.queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
 然后分别取遍历searchList和webSearchInfoList去填充mSearchablesMap对象、mSearchablesList对象
和 mSearchablesInGlobalSearchList对象。
        if (searchList != null || webSearchInfoList != null) {
            int search_count = (searchList == null ? 0 : searchList.size());
            int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
            int count = search_count + web_search_count;
            for (int ii = 0; ii < count; ii++) {
                // for each component, try to find metadata
                ResolveInfo info = (ii < search_count)
                        ? searchList.get(ii)
                        : webSearchInfoList.get(ii - search_count);
                ActivityInfo ai = info.activityInfo;
                // Check first to avoid duplicate entries.
                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);
                        if (searchable.shouldIncludeInGlobalSearch()) {
                            newSearchablesInGlobalSearchList.add(searchable);
                        }
                    }
                }
            }
        }
 那么Searchables五个属性中到底在系统启动的时候存了那些信息呢,我们可以通过在编写一个Android小应用,利用反射查看一些这些信息是什么。通过测试,获得这些属性的包含的值。
mSearchablesList 中存储的是系统中可以"被搜索"到的应用程序的主Activity,当向系统中添加应用时,如果应用在AndroidManifest.xml中被表明是可以被搜索到的,在mSearchablesList 就会有此应用。
mSearchablesMap是mSearchablesList 的Map形式,便于搜索查询相关应用的主Activity。
mGlobalSearchActivity 对应的类是:com.android.quicksearchbox.SearchActivity。
mWebSearchActivity 对应的类是:com.android.quicksearchbox.google.GoogleSearch。
mSearchablesInGlobalSearchList 中存储的对象类型有如下:
com.android.providers.applications.ApplicationLauncher
com.android.mms.ui.SearchActivity
com.android.contacts.SearchResultsActivity
com.android.browser.BookmarkSearch
com.android.music.QueryBrowserActivity
可以看出系统初始的能够被全局搜索的应用有短信、联系人、音乐、浏览器书签和应用程序管理。
 

4. SearchManager提供搜索相关操作

SearchManager是搜索服务的入口,客户端获取SearchManager对象可以调用getSystemService方法来获得。

 

SearchManager searchManager = (SearchManager)this.getSystemService(SEARCH_SERVICE);

可以看到SearchManager内部定义了两个回调接口OnDismissListener和OnCancelListener,并且实现了DialogInterface.OnDismissListener和DialogInterface.OnCancelListener接口,客户端可以通过setOnDismissListener和setOnCancelListener来设置搜索框消失和取消时的事件处理。

SearchManager有个SearchDialog类型的对象mSearchDialog,它就是搜索时显示的搜索框。

看一下SearchManager中的一些重要方法,

 

 

  • public void startSearch(String initialQuery, boolean selectInitialQuery, ComponentName launchActivity, Bundle appSearchData, boolean globalSearch) 
客户端可以通过调用startSearch方法就可以在当前的显示组件上打开搜索框。我们看看这段代码都做了什么。
    public void startSearch(String initialQuery, 
                            boolean selectInitialQuery,
                            ComponentName launchActivity,
                            Bundle appSearchData,
                            boolean globalSearch) {
        if (globalSearch) {
            startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
            return;
        }

        ensureSearchDialog();

        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData);
    }
 在startSearch,它调用了startGlobalSearch方法开启了搜索服务;在ensureSearchDialog中初始化了mSearchDialog对象,设置了它的取消和消失事件;打开了搜索框。
    /* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
            Bundle appSearchData) {
        ComponentName globalSearchActivity = getGlobalSearchActivity();
        if (globalSearchActivity == null) {
            Log.w(TAG, "No global search activity found.");
            return;
        }
        Intent intent = new Intent(INTENT_ACTION_GLOBAL_SEARCH);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setComponent(globalSearchActivity);
        // Make sure that we have a Bundle to put source in
        if (appSearchData == null) {
            appSearchData = new Bundle();
        } else {
            appSearchData = new Bundle(appSearchData);
        }
        // Set source to package name of app that starts global search, if not set already.
        if (!appSearchData.containsKey("source")) {
            appSearchData.putString("source", mContext.getPackageName());
        }
        intent.putExtra(APP_DATA, appSearchData);
        if (!TextUtils.isEmpty(initialQuery)) {
            intent.putExtra(QUERY, initialQuery);
        }
        if (selectInitialQuery) {
            intent.putExtra(EXTRA_SELECT_QUERY, selectInitialQuery);
        }
        try {
            if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0));
            mContext.startActivity(intent);
        } catch (ActivityNotFoundException ex) {
            Log.e(TAG, "Global search activity not found: " + globalSearchActivity);
        }
    }
 可以看到startGlobalSearch做的事情就是打开globalSearchActivity,上面我分析可以知道globalSearchActivity就是com.android.quicksearchbox.SearchActivity,其实就是打开了QuickSearchBox应用的首界面。
  • public void triggerSearch(String query,  ComponentName launchActivity, Bundle appSearchData) 
triggerSearch与startSearch方法类似,只是selectInitialQuery与globalSearch设置为false
  • public void stopSearch() 
相当于触发了SearchManager的cancel事件,将dialog取消掉了
  • public Cursor getSuggestions(SearchableInfo searchable, String query, int limit)

这个方法被标为@hide的,是android内部的api。

 

5.  SuggestionsAdapter填充SearchDialog的下拉框数据

 

6.  SearchRecentSuggestions与SearchRecentSuggestionsProvider辅助实现搜索的历史记录

 

7.  搜索在系统组件中的分布

Activity中有方法onSearchRequested

 

8.  meta-data标签的使用

参考:http://blog.csdn.net/happy_6678/article/details/6556771

 

9.  与ContentProvider相关

参考:http://www.cnblogs.com/over140/archive/2011/12/28/2304393.html

  • 大小: 24.3 KB
分享到:
评论

相关推荐

    浮Android项目动搜索框(SearchManager).rar

    在Android开发中,SearchManager是一个非常重要的组件,它主要用于实现应用程序内的全局搜索功能。这个功能让用户可以在不离开当前界面的情况下快速查找和访问应用中的数据。本文将深入探讨SearchManager的工作原理...

    android浮动搜索框(SearchManager).zip

    本教程将深入探讨如何使用SearchManager来创建一个浮动搜索框,以及相关的源码分析。 一、SearchManager概述 SearchManager是Android系统提供的服务,用于管理系统的全局搜索配置和启动搜索活动。它可以帮助开发者...

    安卓Android源码——百度地图搜索Search.zip

    在安卓开发中,集成百度...综上所述,“安卓Android源码——百度地图搜索Search.zip”项目涵盖了地图应用的核心功能,通过学习和分析这些源码,开发者可以深入了解如何在Android应用中集成并优化百度地图的搜索功能。

    安卓Android源码——QuickSearchBox.rar

    对于开发者,Android提供了`SearchManager`类,用于获取和设置搜索相关的信息,如获取搜索建议,启动搜索活动等。 总的来说,QuickSearchBox是Android系统中不可或缺的一部分,它通过高效地整合系统内外的各种搜索...

    安卓Android源码——百度地图API 之 定位周边搜索POI.zip

    本压缩包“安卓Android源码——百度地图API 之 定位周边搜索POI.zip”显然包含了实现这些功能的源代码示例,主要聚焦在用户位置的获取和周围兴趣点(POI)的搜索上。 首先,我们来讨论一下“定位”这一关键知识点。...

    安卓Android源码——安卓调用百度地图,实现定位和搜索功能.zip

    这个压缩包文件“安卓Android源码——安卓调用百度地图,实现定位和搜索功能.zip”提供了示例代码,帮助开发者了解如何在Android应用中调用百度地图服务。以下是对这些功能的详细讲解: 首先,我们需要在项目中添加...

    基于Android的浮动搜索框(SearchManager).zip

    本项目"基于Android的浮动搜索框(SearchManager)"是专为Android初学者和毕业生设计的学习资源,适用于使用Android Studio、IntelliJ IDEA以及Eclipse等IDE的开发者,尤其是推荐使用Android Studio,因为它是目前...

    浮动搜索框(SearchManager).zip

    通过研究"浮动搜索框(SearchManager).doc"中的源码,你可以深入了解SearchManager的工作原理,学习如何在自己的应用中实现一个高效且用户友好的浮动搜索框。这份文档应该包含了具体的代码示例和实现细节,可以帮助...

    浮动搜索框(SearchManager).doc.zip

    在Android开发中,`SearchManager` 是一个非常重要的组件,它提供了一种高效且用户友好的方式来实现全局搜索功能。浮动搜索框通常指的是在应用界面中可以浮现在其他视图之上,允许用户快速输入查询内容的搜索框。在...

    安卓app开发项目-浮动搜索框(SearchManager)(源码).zip

    本项目聚焦于“安卓app开发项目-浮动搜索框(SearchManager)”,它提供了源码,适合安卓开发的学习者进行毕业设计或者实践。以下是关于这个项目及其相关知识点的详细说明。 1. **浮动搜索框(Floating Search View...

    浮动搜索框(SearchManager)毕业设计—(包含完整源码可运行).zip

    通过研究这些源码,学生不仅可以学习到如何使用SearchManager实现浮动搜索框,还能了解到Android Intent、Activity生命周期、UI组件的使用等基础知识,对于提升Android开发技能非常有帮助。 总结,这个毕业设计项目...

    android系统模块之Contacts的学习笔记

    对于搜索功能,Android提供了SearchManager和Intent ACTION_SEARCH等工具,使得用户可以方便地搜索联系人。 总之,Android系统的Contacts模块是一个综合性的组件,它涉及UI设计、数据管理、用户交互等多个方面。...

    Android---浮动搜索框(SearchManager)(An-Beer工作室)借鉴.pdf

    Android---浮动搜索框(SearchManager)(An-Beer工作室)借鉴.pdf

Global site tag (gtag.js) - Google Analytics