一、何谓Android的过滤机制?

    Android对数据的处理是分层的,从上到下,可以分为:数据层、提供层、Cursor层(不好意思,没找到一个词来表示)、适配层、显示层。每个层次通过一定的机制,可以使数据发生变化时能够上下通知。如下图:
    显示层(ListView,GridView,AutoCompleteTextView等)
    适配层(Adpater)
    Cursor层(Cursor)
    提供层(ContentProvider)
    数据层(文件、sqlite、SharedPreference)
    数据层是数据具体的存储方式,它可以包括文件、sqlite数据库以及SharedPreference。提供层向上层提供了统一的数据调用方式,并负责向其它应用共享数据。Cursor层将查询的数据统一成Cursor的形式来使用。适配层用来连接Cursor层和显示层,将数据和界面连接起来。显示层负责数据的显示。
    另外,Andriod提供了数据的过滤机制,也就是在不改变数据存储的情况下,异步或同步的过滤符合条件的数据,并即时的显示在界面上。
    Android原生的例子当中,最明显的例子就是AutoCompleteTextView,见下图。

    当输入“C程”时,数据库中自动过滤出了还有该字符串的联系人姓名,并显示出来。
    二、Android做了哪些?
    1、为了实现数据的过滤,andorid设计了抽象类Filter,进行异步和同步的数据过滤操作。
    2、在Adapter中继承Filterable,提供给使用者Filter,进行过滤。
    3、在不同的View中,获得查询约束字符串,传递给Adapter,并且提供配合数据过滤的界面支持。
    三、Filter类
    Filter的使用流程如下:
    调用filter方法->在另一线程中调用performFiltering进行数据查询->得到数据过滤结果后调用publishResults将结果返回到使用它的客户端。
    该类中的performFiltering和publishResults均为抽象方法,需要继承者自己重写。
    CursorFilter类就是Filter类的继承。CursorFilter在performFiltering中并没有直接进行数据的过滤,而是加入了CursorFilterClient成员,将过滤的操作转让给了CursorFilterClient,实际上CursorAdpater就是继承了CursorFilterClient接口,也就是说过滤操作实际上是在CursorAdapter中执行的。
    四、Filterable接口
    常用的Adapter基本上都继承了Filterable接口,如CursorAdapter,ArrayAdapter,SimpleAdapter等。该接口只有一个函数,名为getFilter,通过该函数可以通过Adaper获取Filter,然后通过该Filter进行过滤。
    在CursorAdapter中,可以更改过滤的流程,有两种方式:
    1、通过重写CursorAdapter的runQueryOnBackgroundThre ad函数,在函数中根据过滤约束字符串,重新查找生成新的Cursor。Adapter会适时将旧的Cursor进行替换。
    2、通过调用setFilterQueryProvider函数,提供一个FilterQueryProvider,该对象含有runQuery方法,作用同runQueryOnBackgroundThre ad方法相同。
    使用那种方法取决于您是不是重载CursorAdapter,以及您的过滤动作需要在Adpter中实现还是在主程序中实现。
    五、数据过滤功能的View的界面支持。
    为了实现数据过滤的功能,在数据显示层,也有相应的支持。比如ListView和GridView,设置了setFilterText函数,通过该函数可以一方面进行数据的过滤,另一方面显示一个PopupWindow,提示用户输入了那种过滤条件。AutoCompleteTextView当用户在文本框输入文字时,自动进行过滤,并弹出列表显示过滤数据。

六、实战

知道了Android的过滤机制,我们就以AutoCompleteTextView为例,通过输入文本筛选数据库中的数据。

1、首先写ContentProvider
   由于代码量比较多,只写出对外的接口。

  1. public   static   final   class  Location implements BaseColumns {
  2. public  static  final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "location" );
  3. public  static  final String CONTENT_TYPE = "vnd.android.cursor.dir/weather_location";
  4. public  static  final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/weather_location";
  5. public  static  final String CONTENT_DIRECTORY = "location" ;
  6. public  static  final String LOCATION_NAME = "location_name";
  7. public  static  final String LONGITUDE = "longitude" ;
  8. public  static  final String ALTITUDE = "altitude" ;
  9. }

2、写CursorAdapter

  1. private  static   class LocationAdapter  extends CursorAdapter {
  2. private LayoutInflater mInflater;
  3. private Context mContext;
  4. private Cursor mCursor;
  5. public LocationAdapter(Context context, Cursor c) {
  6. super(context, c);
  7. mContext = context;
  8. mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  9. }
  10. @Override
  11. public  void bindView(View view, Context context, Cursor cursor) {
  12. TextView textView = (TextView) view;
  13. String location = cursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME));
  14. textView.setText(location);
  15. }
  16. @Override
  17. public View newView(Context context, Cursor cursor, ViewGroup parent) {
  18. return mInflater.inflate(android.R.layout.simple_dropdown_item_1line, null );
  19. }
  20. @Override
  21. public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
  22. String selection = Location.LOCATION_NAME + " LIKE '%" + constraint + "%'" ;
  23. return mContext.getContentResolver().query(Location.CONTENT_URI
  24. , null, selection,  null ,  null );
  25. }
  26. @Override
  27. public CharSequence convertToString(Cursor cursor) {
  28. return cursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME));
  29. }
  30. }
    3、AutoCompleteTextView与Adapter关联。
  1. private  void initialTextView() {
  2. mTextView = new AutoCompleteTextView(mContext);
  3. mTextView.setThreshold(0);
  4. Cursor cursor = mContext.getContentResolver().query(Location.CONTENT_URI
  5. , null,  null,  null,  null);
  6. LocationAdapter adapter = new LocationAdapter(mContext, cursor);
  7. mTextView.setAdapter(adapter);
  8. }
    需要提醒的是:AutoCompleteTextView内部的数据筛选并没用采用异步筛选的方式,而是直接调用了Filter内部的performFiltering,所以尽量不要在筛选的函数内做太费时间的事情,否则就乎出现不流畅的情况。
    Enjoyit!

对于短信搜索,是直接使用了Android系统的搜索框架,当然在我们平常做项目的时候,也可以直接调用系统自带的搜索框,这个具体的怎么调用可以用Google或者百度搜索,有许多相关的资料,现在主要记录下自己阅读短息搜索源码的流程以及遇到的问题。

1. 在ConversationList.java文件中有如下一段代码:

[java]  viewplain  copy
  1. public   boolean  onSearchRequested() { startSearch( null ,  false ,  null    ,  false );  return   true ;}

在这里是重写了Activity里的onSearchRequested()方法,如果我们不想在这里面做一些操作的话,可以直接调用onSearchRequested()方法。在onSearchRequested()方法里是调用了startSearch()方法。

2.一直追踪下去可以追溯到SearchaDialog.java中。这里在搜索框中添加了一个Adapter,这个Adapter就是来显示下拉列表的,在这个类中发现在runQueryOnBackgroundThread()方法中还是回到了SearchManager的getSuggestions方法中,根据相应的Uri, mContext.getContentResolver().query(uri, null,selection, selArgs, null);去查询相关的数据库。

3.在短信搜索这里与之相关的Uri为SuggestionsProvider,最后还是到了MmsSmsProvider中去进行数据库查询操作。

4.在MmsSmsProvider中有条查询语句:String.format("SELECT _id, index_text,source_id, table_to_use, offsets(words) FROM words WHERE wordsMATCH '%s*' LIMIT 50;", searchString);这里将通过这条SQL语句进行查询,将结果以Cursor的形式进行返回。

4.在SuggestionsProvider,这边对cursor的内容进行提取,显示在下拉列表中。但是这里可能是Google留给广大厂商去解决,就是SQLite中的 MATCH并不能很好的匹配亚洲文字,如:汉字,韩语等。所以按照源码的话,这个短信搜索功能搜索英文还可以,但是搜索亚洲文字,则无法搜索出来。不知道以后SQLite 会不会对 MATCH 增加对非字母文字的支持。

关于offsets(),的一些说明:

offsets(),返回一系列以空格隔开的整数,至少含有4为数(以4个整数为一组返回)。

对于这四位数的解释:

第0位:表示列号

第1位:表示在该列中该字符出现的次数

第2位:在该列中匹配项字符的偏移位 (bytes)

第3位:匹配项的大小(bytes)

offsets()需要和MATCH配对使用。

关于MATCH()

MATCH : 如  MATCH 'Hi', 表示存在Hi的字符串,MATCH ‘Hi*’,表示以Hi开头的字符串。

 

Android为ListView提供了Filter对象,对显示的条目进行过滤。最常见的用法就是Contact中,根据在输入框中输入姓名的字母显示过滤。当然android系统中默认提供的过滤功能非常有限,不支持号码或是其他信息过滤。我曾见过有人为了支持对号码的过滤,就将Android提供的那套机制屏蔽掉,每当过滤事件发生时,手动起AsyncQueryHander去异步查询。当查询完毕时调用CursorAdapter.changeCursor更新Cursor。虽然基本上做法没错,流程上也跟Android实现过滤的机制大体相同,但重复了制造轮子的过程,而原有的轮子,只需稍加修改足以满足新的需求。
     我们只需要重写public Cursor runQueryOnBackgroundThread(CharSequenceconstraint),或者实现接口FilterQueryProvider的对象,再将该对象setFilterQueryProvider给CursorAdapter即可。
     下面分析下CursorAdapter与Filter的实现框架。
     先说下Filter:
     Filter与AsyncQueryHander实现基本类似,它包含两个Hander:RequestHandler和ResultHandler,以及一个HandlerThread:名为Filter的线程。RequestHandler与Filter线程绑定,过滤请求都是通过RequestHandler发送给Filter线程。当过滤产生后,通过mResultHandler将数据push给UI显示。
     CursorFilter继承Filter,它提供了CursorFilterClient接口,CursorAdapter实现CursorFilterClient接口。CursorFilter会在过滤的某些点回调CursorFilterClient接口的对应函数,我们就是通过这些被回调的函数,改变Filter的行为,以实现自己的目的。这与我们熟知的Activity生命周期上的:onCreate->onResume->onPause......的做法类似。
     来看下这个重要的接口CursorFilterClient的定义 
     interface CursorFilterClient {
       CharSequence convertToString(Cursor cursor);
       Cursor runQueryOnBackgroundThread(CharSequence constraint);
       Cursor getCursor();
       void changeCursor(Cursor cursor);
    }
    runQueryOnBackgroundThread是运行在Filter线程中,返回的Cursor将传给ResultHandler,最后传给UI显示。所以上面的例子中,我们要添加对号码的查询,只需在这里自己组织下查询条件,包含对号码的查询,找数据库查询下,将查询结果返回即可。
    changeCursor在ResultHandler向UI送结果时被调用,通过它更新显示过滤后的数据。我们可以重载它,在过滤数据显示前,做点需要的事情(比如更新下SectionIndexer)。
    getCursor只是返回下Adapter中保存的Cursor,convertToString在CursorAdapter没有被用到,不管它了。

android filter相关推荐

  1. Android Drawable 详解(教你画画!)

    参考 1.Android中的Drawable基础与自定义Drawable 2.android中的drawable资源 3.Android开发之Shape详细解读 Drawable分类 No xml标签 ...

  2. android bitmap转图片_Android 这些 Drawable 你都会用吗?

    在实际开发的过程中,除了广为人知的利用 StateListDrawable 设置按钮点击特效,我们有时可能会接到一些这样的需求,比如要求我们的头像显示成圆形或者圆角矩形,甚至要加上可变颜色的边框,或者 ...

  3. 你都知道么?Android中21种drawable标签大全

    前言 我们在drawable目录下可以创建很多自定义的资源,其中用的最多的应该就是selector和shape.目前在Android中有21种drawable标签,了解和利用这些标签对我们的开发有很大 ...

  4. android bitmap xml,XML Bitmap

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 目录: 定义 一个XML bitmap是一个在XML文件中定义的指向一个bitmap文件的资源.其效果是作为一个原始位图 ...

  5. android drawable 比例,Android中的Drawable基础与自定义Drawable

    转载请注明链接:http://blog..net/feather_wch/article/details/79124608 本文要点: 1. 介绍Android中Drawable的相关知识点,并且介绍 ...

  6. Android 应用开发(12)---可绘制对象资源

    可绘制对象资源 可绘制对象资源是一般概念,是指可在屏幕上绘制的图形,以及可以使用 getDrawable(int) 等 API 检索或者应用到具有 android:drawable 和 android ...

  7. Android Multimedia框架总结(二十八)NuPlayer到OMX过程

    原址 NuPlayer是谷歌新研发的.  AwesomePlayer存在BUG,谷歌早已在android m 版本中弃用. sp<MediaPlayerBase> MediaPlayerS ...

  8. android中drawable的自建资源

    Drawable 资源图:bitmap shape layer stateList bitmap :<?xml version="1.0" encoding="ut ...

  9. ANDROID XML图像资源文件详细讲解(一)

    图像资源在android开发过程中使用非常平凡.为了让自己在开发中,能轻松解决任何有关图像的问题,所以必须全面掌握最基本的知识点----各种类型的图像资源文件. 前言: 前言的前言:因为内容较多,此系 ...

最新文章

  1. Debain 7.2安装配置
  2. Knative 初体验:CICD 极速入门
  3. Nebula:Slack 的覆盖全球性的开源网络
  4. 做网页前端遇到的一些问题
  5. python情感词典计算得分_利用情感词典计算调研纪要中的情感得分
  6. xlsx文件打开乱码_excel表格文件打开都是乱码怎么解决
  7. 安卓版有道词典的离线词库-《21世纪大英汉词典》等_我是亲民_新浪博客
  8. VC资源编辑器里对话框的大小和实际的像素尺寸显示问题
  9. VML标记与通用属性
  10. ES部分查询方法,elasticsearch查询方法
  11. 【高等数学基础进阶】导数与微分
  12. Deployer php自动部署,Deployer 自动部署
  13. 电子计算机的四个名称,文件夹,文件夹名称唯美四个
  14. hadoop安装过程命令汇总
  15. GAL汉化界的一点实话。。。。。
  16. 汽车养护及美容【1】
  17. vue中打开一个新页面
  18. java商城系统源码谁有,b2b2c或b2c的,类似iskyshop,legendshop,shop
  19. 计算机毕业设计Java养老院信息管理(系统+源码+mysql数据库+Lw文档)
  20. 安装禅道系统(开源)和配置RDS数据库

热门文章

  1. oracle sequence job
  2. ElementUI使用按钮进行图片预览
  3. 3D Human Body Reconstruction from a Single Image via Volumetric Regression笔记
  4. 计算机英语五人对话,一篇5人英语小对话,-五人英语对话加翻译-井睾品同学
  5. 搭建智能语音交互系统
  6. 【报告分享】新消费品牌发展报告-WEIQ(附下载)
  7. Android混淆后的日志查看方法(mac)
  8. 字符串中去掉特定字符
  9. 电脑的基本故障与解决方法
  10. win10如何打开摄像头_win7摄像头不见了怎么办?试试这个方法,摄像头立马出现...