Filter实现原理及内部流程

来源:互联网 发布:武极天下坐骑进阶数据 编辑:程序博客网 时间:2024/06/14 10:32

一、Filter简介 

APi中对Filter的描述极为精简,就是通过用户设置的过滤条件,通过Filter内部的一系列操作(对数据的过滤处理通常通过线程异步操作)实现过滤条件,最终获得过滤后的结果。一般通过实现Filterable接口调用(自定义的)Filter。


1、Filterable
Filterable定义一过滤行为,利用Filter对数据进行过滤处理。Filterable通常实现对Adapt的限制。
Public interface Filterable{    //Returns a filter that can be used to constrain data with a filtering pattern.    //This method is usually implemented by android.widget.Adapter classes.    Filter getFilter();}


2、Filter

Filter通过定义的filter pattern实现对数据的过滤行为,对数据的过滤操作是异步实现的,通过调用filter(CharSequence)或filter(CharSequence, android.widget.Filter.FilterListener)实现,如果这两个方法被调用,先前还未被执行的异步操作将被取消,而只是执行此次调用的异步操作。Filter通常由Filterable创建,即Filter getFilter(),此处得到的Filter必然是用户自定义的,通常需要实现

 FilterResults performFiltering(CharSequence constraint)
<pre name="code" class="java">publishResults(CharSequence,android.widget.Filter.FilterResults)

源码如下:

<pre name="code" class="java">public abstract class Filter {          //执行异步过滤操作,调用此方法将会终止所有先前还未被执行的异步操作    public final void filter(CharSequence constraint) {        filter(constraint, null);    }        //upon completion of the operation,the listener is notified    public final void filter(CharSequence constraint, FilterListener listener)        //在线程中调用该方法,根据提供的 constraint执行过滤操作,该操作返回FilterResults    //在UI线程中,通过调用publishResults(CharSequence,android.widget.Filter.FilterResults)返回FilterResults    protected abstract FilterResults performFiltering(CharSequence constraint);        //在线程中调用此函数,将过滤后的结果FilterResults更新到UI界面,    protected abstract void publishResults(CharSequence constraint,FilterResults results);      //将过滤后的Item转换成字符串,根据实际需要重写    public CharSequence convertResultToString(Object resultValue) {        return resultValue == null ? "" : resultValue.toString();    }        //保存过滤操作后得到的结果,实际上就是一个数据封装    protected static class FilterResults {        public FilterResults() {                   }        // Contains all the values computed by the filtering operation.        //一般是数组或Arraylist        public Object values;        //values个数        public int count;    }        //Listener used to receive a notification upon completion of a filtering operation    public static interface FilterListener {    //Notifies the end of a filtering operation    public void onFilterComplete(int count);    }}




二、AutoCompleteTextView利用ArrayAdapter实现提示原理

实现一个完整的Filter流程,一般是两个步骤:一是实现对数据的过滤操作,获得过滤结果后,通过观察者模式获知数据发生变化,并进行后续处理;二是在过滤操作完成后,调用监听器接口实现自定义操作:public static interface FilterListener 


1、ArrayAdapter 
ArrayAdapter实现继承自Filter的内部类ArrayFilter,主要是实现两个函数:
performFiltering,主要是对ArrayAdapter中的数据项实现对某个前缀的匹配操作,并获得匹配的数据项;publishResults,获得符合过滤条件的结果后,通过观察者模式,实现刷新等操作。

public class ArrayAdapter<T> extends BaseAdapter implements Filterable {    public Filter getFilter() {        if (mFilter == null) {            mFilter = new ArrayFilter();        }        return mFilter;    }    /**     * An array filter constrains the content of the array adapter with  a prefix.      * Each item that does not start with the supplied prefix  is removed from the list.     */         private class ArrayFilter extends Filter {        @Override        protected FilterResults performFiltering(CharSequence prefix) {                    FilterResults results = new FilterResults();            if (mOriginalValues == null) {                synchronized (mLock) {                    mOriginalValues = new ArrayList<T>(mObjects);                }            }            if (prefix == null || prefix.length() == 0) {                ArrayList<T> list;                synchronized (mLock) {                    list = new ArrayList<T>(mOriginalValues);                }                results.values = list;                results.count = list.size();            } else {                String prefixString = prefix.toString().toLowerCase();                ArrayList<T> values;                synchronized (mLock) {                    values = new ArrayList<T>(mOriginalValues);                }                final int count = values.size();                final ArrayList<T> newValues = new ArrayList<T>();                for (int i = 0; i < count; i++) {                    final T value = values.get(i);                    final String valueText = value.toString().toLowerCase();                    // First match against the whole, non-splitted value                    if (valueText.startsWith(prefixString)) {                        newValues.add(value);                    } else {                        final String[] words = valueText.split(" ");                        final int wordCount = words.length;                        // Start at index 0, in case valueText starts with space(s)                        for (int k = 0; k < wordCount; k++) {                            if (words[k].startsWith(prefixString)) {                                newValues.add(value);                                break;                            }                        }                    }                }                results.values = newValues;                results.count = newValues.size();            }            return results;        }        @Override        protected void publishResults(CharSequence constraint, FilterResults results) {            //noinspection unchecked            mObjects = (List<T>) results.values;            if (results.count > 0) {                notifyDataSetChanged();            } else {                notifyDataSetInvalidated();            }       }}

2、AutoCompleteTextView

实现Filter中的接口Filter.FilterListener


public class AutoCompleteTextView extends EditText implements Filter.FilterListener {    public void onFilterComplete(int count) {        updateDropDownForFilter(count);    }    private void updateDropDownForFilter(int count) {        // Not attached to window, don't update drop-down        if (getWindowVisibility() == View.GONE) return;        /*         * This checks enoughToFilter() again because filtering requests         * are asynchronous, so the result may come back after enough text         * has since been deleted to make it no longer appropriate         * to filter.         */        final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();        final boolean enoughToFilter = enoughToFilter();        if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter) {            if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) {                showDropDown();            }        } else if (!dropDownAlwaysVisible && isPopupShowing()) {            dismissDropDown();            // When the filter text is changed, the first update from the adapter may show an empty            // count (when the query is being performed on the network). Future updates when some            // content has been retrieved should still be able to update the list.            mPopupCanBeUpdated = true;        }    }

三、自定义Filter

ArrayAdapter只能实现一个TextView,通过自定义一个ContactAdapter,实现两个TextView,配合AutoCompleteTextview使用

自定义ContactAdapter:

package com.study.contactadapter;import java.util.ArrayList;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.Filter;import android.widget.Filterable;import android.widget.TextView;import com.example.autotipphonenumber.R;import com.study.remind.Contact;public class ContactAdapter extends BaseAdapter implements Filterable{private Context context;private ArrayList<Contact> Datas;private LayoutInflater inflater;public ContactAdapter(Context context,ArrayList<Contact> Datas){this.context=context;this.Datas=Datas;//设置inflater的两种方式//inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);inflater=LayoutInflater.from(context);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn Datas.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn Datas.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View root = inflater.inflate(R.layout.contcat,null);TextView name=(TextView) root.findViewById(R.id.name);TextView phoneNum=(TextView) root.findViewById(R.id.phoneNum);name.setText(Datas.get(position).getName());phoneNum.setText(Datas.get(position).getPhoneNum());return root;}//实现Filterabale接口@Overridepublic Filter getFilter() {return new ContactFilter();}private class ContactFilter extends Filter{@Override//两个textview中的任意一个<span style="font-family: KaiTi_GB2312;">首字母符合过滤条件,则将其加入到过滤结果中</span>
protected FilterResults performFiltering(CharSequence constraint) {FilterResults results = new FilterResults();ArrayList<Contact> filterResult=new ArrayList<Contact>();for(int i=0;i<Datas.size();i++){if(Datas.get(i).getName().startsWith((String) constraint) || Datas.get(i).getPhoneNum().startsWith((String) constraint) ){filterResult.add(Datas.get(i));}}            results.values = filterResult;            results.count = filterResult.size();return results;}@Overrideprotected void publishResults(CharSequence constraint,FilterResults results) {            if (results.count > 0) {                notifyDataSetChanged();            } else {                notifyDataSetInvalidated();            }}}}

MainActivity源码:


package com.example.autotipphonenumber;import java.util.ArrayList;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.AdapterView.OnItemSelectedListener;import android.widget.AutoCompleteTextView;import com.study.contactadapter.ContactAdapter;import com.study.remind.Contact;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final AutoCompleteTextView autoTip=(AutoCompleteTextView) this.findViewById(R.id.autoTip);autoTip.setThreshold(1);//初始化数据ArrayList<Contact> Contacts=Contact.generateContact();//自定义adapterContactAdapter adapter=new ContactAdapter(this,Contacts);autoTip.setAdapter(adapter);//设置点击事件获取文本autoTip.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {Contact contact=(Contact) parent.getItemAtPosition(position);autoTip.setText(contact.getPhoneNum());}});}}

结果:



0 0
原创粉丝点击