`

android filter

 
阅读更多

一、何谓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的runQueryOnBackgroundThread函数,在函数中根据过滤约束字符串,重新查找生成新的Cursor。Adapter会适时将旧的Cursor进行替换。
   2、通过调用setFilterQueryProvider函数,提供一个FilterQueryProvider,该对象含有runQuery方法,作用同runQueryOnBackgroundThread方法相同。
   使用那种方法取决于您是不是重载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.  
  7.     public  static  final String LOCATION_NAME = "location_name"; 
  8.     public  static  final String LONGITUDE = "longitude" ; 
  9.     public  static  final String ALTITUDE = "altitude" ; 

   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.  
  11.     @Override 
  12.     public  void bindView(View view, Context context, Cursor cursor) { 
  13.         TextView textView = (TextView) view; 
  14.         String location = cursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME)); 
  15.         textView.setText(location); 
  16.     } 
  17.  
  18.     @Override 
  19.     public View newView(Context context, Cursor cursor, ViewGroup parent) { 
  20.         return mInflater.inflate(android.R.layout.simple_dropdown_item_1line, null ); 
  21.     } 
  22.      
  23.     @Override 
  24.     public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 
  25.         String selection = Location.LOCATION_NAME + " LIKE '%" + constraint + "%'" ; 
  26.         return mContext.getContentResolver().query(Location.CONTENT_URI 
  27.                 , null, selection,  null ,  null ); 
  28.     } 
  29.      
  30.      
  31.     @Override 
  32.     public CharSequence convertToString(Cursor cursor) { 
  33.         return cursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME)); 
  34.     } 
   3、AutoCompleteTextView与Adapter关联。
 
  1. private  void initialTextView() { 
  2.     mTextView = new AutoCompleteTextView(mContext); 
  3.     mTextView.setThreshold(0); 
  4.      
  5.     Cursor cursor = mContext.getContentResolver().query(Location.CONTENT_URI 
  6.             , null,  null,  null,  null); 
  7.     LocationAdapter adapter = new LocationAdapter(mContext, cursor); 
  8.     mTextView.setAdapter(adapter); 
   需要提醒的是: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

    在Android开发中,`Filter`是一个非常重要的概念,它主要用于数据的筛选和过滤,尤其是在处理大量数据时,如ListView、RecyclerView等组件的数据展示。本文将深入探讨`Android Filter`的原理及其在过滤ListView变色...

    Android Intent Filter用法

    在Android应用开发中,Intent Filter是一个至关重要的概念,它用于定义一个组件(如Activity或BroadcastReceiver)能够响应的Intent类型。Intent Filter就像一个过滤器,筛选出应用可以处理的特定操作,使得系统能够...

    Android代码-ND Filter

    Android app for neutral density filter calculation. The play store version is uploaded at https://play.google.com/store/apps/details?id=org.kaziprst.android.ndfilter. Please donate translations for ...

    android-image-filter-ndk,使用android ndk在c中处理位图的android示例项目.zip

    本项目"android-image-filter-ndk"是一个开源示例,它展示了如何利用NDK在C语言中处理Android位图,实现图像过滤器功能。 一、Android NDK基础 1. NDK的作用:NDK为Android应用提供了本地编程环境,使得开发者可以...

    Android GPS及filter实现

    为了解决这个问题,可以使用滤波算法,如卡尔曼滤波(Kalman Filter)、均值滤波、中位数滤波等。例如,卡尔曼滤波是一种有效的在线滤波算法,适用于处理带有随机噪声的数据,可以平滑GPS数据,减少跳跃性误差。 三...

    500px-android-blur.zip

    1. `BlurMaskFilter`: 这是一个自定义的Android Filter,用于对视图进行模糊处理。它使用了OpenGL ES来加速处理过程,提高性能。 2. `BlurringView`: 这是一个自定义视图类,可以将任何子视图的内容模糊化。它提供...

    NXP QCA6174 android wcnss_filter source code

    《NXP QCA6174 Android 蓝牙驱动wcnss_filter源码解析》 在Android系统中,蓝牙功能扮演着至关重要的角色,它使得设备之间能够进行无线通信,实现音频播放、数据传输等功能。NXP QCA6174是一款高性能的Wi-Fi和蓝牙...

    android-instagram-filter, 像 Instagram 这样的android图像过滤器.zip

    android-instagram-filter, 像 Instagram 这样的android图像过滤器 用于Android的 Instagram 过滤器面向Android的 GPUImage概念来自: iOS GPUImage框架。目标是尽可能地拥有类似于GPUImage的东西。 顶点和 fragment...

    Android代码-Photo Effects

    android-image-filter some android image filters in some filter, I use NDK to implement to make it more efficient Setup Install Android NDK and properly configure it: http://goo.gl/koTCb Get a clean ...

    android-instagram-image-filter, 模仿instagram的滤镜(和in的滤镜类似).zip

    这个开源项目“android-instagram-image-filter”提供了一种实现这一功能的方式,它的目标是复制Instagram应用中的滤镜效果,使开发者可以为自己的应用程序添加类似的图像处理功能。 首先,我们来探讨一下滤镜的...

    filter-dialog-activity,Android项目的筛选对话框活动.zip

    在Android开发中,"筛选对话框活动"是常见的用户交互...以上就是与"filter-dialog-activity"这个开源项目相关的Android开发知识点,通过学习和应用这些知识,开发者可以提升其在创建高效、易用筛选对话框方面的技能。

    Android studio sdk 源码 android-23

    开发者需要在AndroidManifest.xml中配置相应的intent-filter,以实现应用间的深度链接。 4. Android Studio支持:Android Studio 1.5及以上版本提供了对Android 23的全面支持,包括Gradle插件更新,使得构建过程...

    android 实现列表搜索

    本篇将详细介绍如何在Android应用中实现列表搜索,主要涉及`filter`概念以及实际的代码实现。 一、Filter原理 `Filter`是Java和Android中的一个接口,用于数据过滤。在Android中,`Filter`通常与`Adapter`一起使用...

    android手把手教你开发launcher(AndroidStudio版)

    在Android中,intent-filter定义了组件可以响应的Intent。Intent可以认为是一种消息传递方式,它告诉Android系统某个组件(如Activity)能够执行哪些操作。一个Activity通过在AndroidManifest.xml文件中配置intent-...

    Android开发之EditText字符串过滤器InputFilter

    在Android开发中,EditText是用户输入数据的常见组件,它允许用户输入文本并显示在界面上。然而,有时候我们希望对用户的输入进行限制,比如只允许输入数字、字母或者特定格式的数据,这时我们就需要用到EditText的...

    Data、Type属性与Intent-filter配置

    在Android应用开发中,Intent是连接应用程序组件之间通信的关键机制。Intent-filter的配置对于正确地启动和接收...在Android系统中,Intent-filter是组件间通信的关键组成部分,它决定了哪些组件能响应用户的特定操作。

    android 8.1设置添加Ethernet功能选项

    <category android:name="com.android.settings.SHORTCUT" />+ </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value=...

    Android代码-CameraFilter

    CameraFilter Realtime camera filters. Process frames by OpenGL shaders. Download the apk to have a try. Filters Thanks to the original authors of the shader codes. I had only portted them from webgl ...

    Android-logback-android用于Android的可靠通用快速和灵活的日志记录框架

    `logback-android`支持插件机制,允许开发者编写自定义的Appender、Filter和Layout。这为日志系统提供了极高的灵活性,可以根据项目需求定制各种高级功能。 综上所述,`logback-android`作为Android开发中的日志...

Global site tag (gtag.js) - Google Analytics