android filter
一、何谓Android的过滤机制?
Android对数据的处理是分层的,从上到下,可以分为:数据层、提供层、Cursor层(不好意思,没找到一个词来表示)、适配层、显示层。每个层次通过一定的机制,可以使数据发生变化时能够上下通知。如下图: 显示层(ListView,GridView,AutoCompleteTextView等) 适配层(Adpater) Cursor层(Cursor) 提供层(ContentProvider) 数据层(文件、sqlite、SharedPreference) 数据层是数据具体的存储方式,它可以包括文件、sqlite数据库以及SharedPreference。提供层向上层提供了统一的数据调用方式,并负责向其它应用共享数据。Cursor层将查询的数据统一成Cursor的形式来使用。适配层用来连接Cursor层和显示层,将数据和界面连接起来。显示层负责数据的显示。 另外,Andriod提供了数据的过滤机制,也就是在不改变数据存储的情况下,异步或同步的过滤符合条件的数据,并即时的显示在界面上。 Android原生的例子当中,最明显的例子就是AutoCompleteTextView,见下图。filter" style="border-style: none; max-width: 100%;" src="https://img.it610.com/image/product/8192950494e34b6bb28e76fb20afee9d.jpg" width="240" height="320">
当输入“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当用户在文本框输入文字时,自动进行过滤,并弹出列表显示过滤数据。filter" style="border-style: none; max-width: 100%;" src="https://img.it610.com/image/product/b5e351c9df9a4aa9b01514a2b5b13916.png" width="240" height="320">
六、实战
知道了Android的过滤机制,我们就以AutoCompleteTextView为例,通过输入文本筛选数据库中的数据。
1、首先写ContentProvider
由于代码量比较多,只写出对外的接口。
- publicstaticfinalclassLocationimplementsBaseColumns{
- publicstaticfinalUriCONTENT_URI=Uri.withAppendedPath(AUTHORITY_URI,"location");
- publicstaticfinalStringCONTENT_TYPE="vnd.android.cursor.dir/weather_location";
- publicstaticfinalStringCONTENT_ITEM_TYPE="vnd.android.cursor.item/weather_location";
- publicstaticfinalStringCONTENT_DIRECTORY="location";
- publicstaticfinalStringLOCATION_NAME="location_name";
- publicstaticfinalStringLONGITUDE="longitude";
- publicstaticfinalStringALTITUDE="altitude";
- }
2、写CursorAdapter
- privatestaticclassLocationAdapterextendsCursorAdapter{
- privateLayoutInflatermInflater;
- privateContextmContext;
- privateCursormCursor;
- publicLocationAdapter(Contextcontext,Cursorc){
- super(context,c);
- mContext=context;
- mInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
- @Override
- publicvoidbindView(Viewview,Contextcontext,Cursorcursor){
- TextViewtextView=(TextView)view;
- Stringlocation=cursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME));
- textView.setText(location);
- }
- @Override
- publicViewnewView(Contextcontext,Cursorcursor,ViewGroupparent){
- returnmInflater.inflate(android.R.layout.simple_dropdown_item_1line,null);
- }
- @Override
- publicCursorrunQueryOnBackgroundThread(CharSequenceconstraint){
- Stringselection=Location.LOCATION_NAME+"LIKE'%"+constraint+"%'";
- returnmContext.getContentResolver().query(Location.CONTENT_URI
- ,null,selection,null,null);
- }
- @Override
- publicCharSequenceconvertToString(Cursorcursor){
- returncursor.getString(cursor.getColumnIndex(Location.LOCATION_NAME));
- }
- }
- privatevoidinitialTextView(){
- mTextView=newAutoCompleteTextView(mContext);
- mTextView.setThreshold(0);
- Cursorcursor=mContext.getContentResolver().query(Location.CONTENT_URI
- ,null,null,null,null);
- LocationAdapteradapter=newLocationAdapter(mContext,cursor);
- mTextView.setAdapter(adapter);
- }
filter" style="border-style: none; max-width: 100%;" src="https://img.it610.com/image/product/4e9c3909fe994efc83f6772746918f92.jpg" width="240" height="320">
对于短信搜索,是直接使用了Android系统的搜索框架,当然在我们平常做项目的时候,也可以直接调用系统自带的搜索框,这个具体的怎么调用可以用Google或者百度搜索,有许多相关的资料,现在主要记录下自己阅读短息搜索源码的流程以及遇到的问题。
1. 在ConversationList.java文件中有如下一段代码:
[java] viewplain copy- publicbooleanonSearchRequested(){startSearch(null,false,null,false);returntrue;}
在这里是重写了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实现过滤的机制大体相同,但重复了制造轮子的过程,而原有的轮子,只需稍加修改足以满足新的需求。 |
更多相关文章
- mybatisplus的坑 insert标签insert into select无参数问题的解决
- python起点网月票榜字体反爬案例
- 10天学通Android开发(7)-数据存储
- 用python第三方库(surface_stats_collector.py) 获取 Android(安
- Android(安卓)content provider基础与使用
- Android(安卓)ImageView 总结
- Android把activity设置为窗口样式怎么去掉标题
- Android下Activity全屏显示实现方法
- Android利用Fiddler进行网络数据抓包