目标 输入关键字,实时显示搜索结果。
作者:木鸟杂记 https://www.qtmuniao.com , 转载请注明出处 
过程 从官方文档 入手,由于初入门,相关术语懂得少,而该文档又非代码级实现,导致没能完整搭起搜索的架子。该文档主要讲了以下几点:
两种实现方式,search dialog和search widget;对于Android 3.0 以后的机器,推荐使用后者,较为灵活。 
三个主要组件:
搜索配置(a searchable configuration) 
搜索容器(a searchable Activity)(困惑点1) 
搜索结构(a search interface) 
 
 
搜索过程:
接受查询(Receive the query) 
查询数据(Search your data) 
呈现结果(Present the results)(困惑点3) 
 
 
 
我想使用Search Widget方式,主要遇到以下几个困惑点:
如何在Activity中触发搜索,就是AppBar右上角的搜索图标如何做出来。 
如果使用Intent的查询数据,如示例一般,应该不能做到实时匹配输入字符。我猜想应该有listener之类的,但是例子没给。 
如何呈现结果,文档建议让SearchAbleActivity继承ListView来实现,但是具体细节,如怎么接受结果,传递给ListView,都没有提。 
 
于是搜索关键词 SearchView action bar,找到一篇帖子:Implementing SearchView in action bar ,反复琢磨,才弄清楚了以上几个问题。
首先,对于触发搜索,该回答使用的是具有App Bar的Activity作为SearchableActivity,并且在复写onCreateOptionsMenu函数,实例化其参数menu,并且将SearchView作为其一个item。如此一来,SearchableActivity的右上角就会有搜索按钮。相关代码如下:res\menu\search.xml: 
1 2 3 4 5 6 7 8 9 <?xml version="1.0"  encoding="utf-8" ?> <menu  xmlns:android ="http://schemas.android.com/apk/res/android"      xmlns:app ="http://schemas.android.com/apk/res-auto" >         <item  android:id ="@+id/search_menu"               android:title ="@string/search_hint"              app:showAsAction ="ifRoom|collapseActionView"              app:actionViewClass ="android.widget.SearchView"  /> </menu > 
SearchableActivity.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override public  boolean  onCreateOptionsMenu (Menu menu)  {    getMenuInflater().inflate(R.menu.search, menu);     this .menu = menu;          SearchManager  searchManager  =  (SearchManager) getSystemService(Context.SEARCH_SERVICE);     SearchView  searchView  =  (SearchView) menu.findItem(R.id.search_menu).getActionView();          ComponentName  name  =  getComponentName();     searchView.setSearchableInfo(searchManager.getSearchableInfo(name));     searchView.setIconifiedByDefault(false );     searchView.setOnQueryTextListener(new  SearchView .OnQueryTextListener() {         @Override          public  boolean  onQueryTextSubmit (String s)  {             doMySearch(s);             return  false ;         }         @Override          public  boolean  onQueryTextChange (String s)  {             doMySearch(s);             return  false ;         }     });     return  true ; } 
AndroidManifest.xml 
1 2 3 4 5 6 7 <activity android:name=".SearchableActivity">     <intent-filter>         <action android:name="android.intent.action.SEARCH" />     </intent-filter>     <meta-data android:name="android.app.searchable"         android:resource="@xml/searchable"/> </activity> 
res/xml/searchable.xml 
1 2 3 4 5 <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android"     android:label="@string/app_label"     android:hint="@string/app_label" > </searchable> 
其次是实时匹配查询结果;也是在onCreateOptionsMenu函数中,给SearchView设置listeners,具体可以见上面代码,但是return true/false暂时有什么区别还没搞清楚。
最后是展示数据;如官方文档所说,利用ListView,具体做法是通过Adapter将数据(比如List)传给利用xml渲染(inflate)的ListView,该答案是用CursorAdaptor(对接数据库数据更合适)。具体代码如下:res/layout/item.xml  
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="match_parent">     <TextView     android:id="@+id/item"     android:layout_width="wrap_content"     android:layout_height="wrap_content" /> </RelativeLayout> 
ResultAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  class  ResultAdapter  extends  CursorAdapter  {    private  List<String> items;     private  TextView text;     public  ResultAdapter (Context context, Cursor cursor, List<String> items)  {         super (context, cursor, false );         this .items = items;     }     @Override      public  void  bindView (View view, Context context, Cursor cursor)  {         text.setText(items.get(cursor.getPosition()));     }     @Override      public  View newView (Context context, Cursor cursor, ViewGroup parent)  {         LayoutInflater  inflater  =  (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);         View  view  =  inflater.inflate(R.layout.item, parent, false );         text = view.findViewById(R.id.item);         return  view;     } } 
SearchableActivity.java 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private  void  doMySearch (String query) {    String[] columns = new  String [] { "_id" , "text"  };     Object[] temp = new  Object [] { 0 , "default"  };     MatrixCursor  cursor  =  new  MatrixCursor (columns);     for (int  i  =  0 ; i < items.size(); i++) {         temp[0 ] = i;         temp[1 ] = items.get(i);         cursor.addRow(temp);     }          final  SearchView  search  =  (SearchView) menu.findItem(R.id.search_menu).getActionView();     search.setSuggestionsAdapter(new  ResultAdapter (this , cursor, items)); } 
参考资料: 
Android官方文档,https://developer.android.com/guide/topics/search/search-dialog.html  
Stack Overflow回答,https://stackoverflow.com/questions/21585326/implementing-searchview-in-action-bar  
官方视频,https://www.youtube.com/watch?v=9OWmnYPX1uc  
 
         
我是青藤木鸟,一个喜欢摄影、专注大规模数据系统的程序员,欢迎关注我的公众号:“木鸟杂记 ”,有更多的分布式系统、存储和数据库相关的文章,欢迎关注。
关注公众号后,回复“资料 ”可以获取我总结一份分布式数据库学习资料。
回复“优惠券 ”可以获取我的大规模数据系统付费专栏《系统日知录 》的八折优惠券。
我们还有相关的分布式系统和数据库的群,可以添加我的微信号:qtmuniao,我拉你入群。加我时记得备注:“分布式系统群”。
另外,如果你不想加群,还有一个分布式系统和数据库的论坛(点这里 ),欢迎来玩耍。