Filter在AbsListView中的使用

来源:互联网 发布:查看udp端口是否开放 编辑:程序博客网 时间:2024/05/16 10:31

       上一篇文章中说到ListAdapter的实现类都实现了Filterable这个接口,这个接口只有一个方法getFilter(),那么这个方法在什么地方被调用的呢?

        翻开AbsListView的源码找到了答案。先看下面两段代码

   /**     * Sets the initial value for the text filter.     * @param filterText The text to use for the filter.     *     * @see #setTextFilterEnabled     */    public void setFilterText(String filterText) {        // TODO: Should we check for acceptFilter()?        if (<span style="color:#ff6600;">mTextFilterEnabled</span> && !TextUtils.isEmpty(filterText)) {            createTextFilter(false);            // This is going to call our listener onTextChanged, but we might not            // be ready to bring up a window yet            <span style="color:#ff6600;">mTextFilter.setText(filterText);            mTextFilter.setSelection(filterText.length());</span>            if (mAdapter instanceof Filterable) {                // if mPopup is non-null, then onTextChanged will do the filtering                if (mPopup == null) {                    <span style="color:#ff6600;">Filter f = ((Filterable) mAdapter).getFilter();                    f.filter(filterText);</span>                }                // Set filtered to true so we will display the filter window when our main                // window is ready                mFiltered = true;                mDataSetObserver.clearSavedState();            }        }    }

   /**     * For our text watcher that is associated with the text filter. Performs     * the actual filtering as the text changes, and takes care of hiding and     * showing the popup displaying the currently entered filter text.     */    public void onTextChanged(CharSequence s, int start, int before, int count) {        if (mPopup != null && <span style="color:#ff6600;">isTextFilterEnabled</span>()) {            int length = s.length();            boolean showing = mPopup.isShowing();            if (!showing && length > 0) {                // Show the filter popup if necessary                showPopup();                mFiltered = true;            } else if (showing && length == 0) {                // Remove the filter popup if the user has cleared all text                dismissPopup();                mFiltered = false;            }            if (mAdapter instanceof Filterable) {                Filter f = ((Filterable) mAdapter).getFilter();                // Filter should not be null when we reach this part                if (f != null) {                    f.filter(s, this);                } else {                    throw new IllegalStateException("You cannot call onTextChanged with a non "                            + "filterable adapter");                }            }        }    }

        从上面的代码可以看到,要使得设置的Filter对象起作用,需要设置mTextFilterEnabled==true,这个设置需要调用方法setTextFilterEnabled(boolean)进行设置。

        另外,第一段代码中有个mTextFilter是一个EditText对象,这个对象是AbsListView对象的默认权限元素,当设置了mTextFilterEnabled==true和filterText,这两个值后,就会对ListView的列表元素起过滤作用。

       /**         * Used with type filter window         */        EditText mTextFilter;</span>

        以ArrayAdapter为例,执行下面的代码:

        ImageView headerView = new ImageView(this);        headerView.setImageResource(R.drawable.ic_launcher);        listView.addHeaderView(headerView);        ImageView footerView = new ImageView(this);        footerView.setImageResource(R.drawable.sample);        listView.addFooterView(footerView,"hello image view",true);        listView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,                new String[]{"孙悟空","猪八戒","沙僧","唐僧","孙悟空","猪八戒","沙僧","唐僧","孙悟空","猪八戒","沙僧","唐僧"}));        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {                Toast.makeText(MyActivity.this, "点击了第" + i + "项", Toast.LENGTH_LONG).show();            }        });        listView.setTextFilterEnabled(true);        listView.setFilterText("孙悟空");

执行结果如下图所示,显示了mTextFilter对象,并且过滤掉所有不包含filterText--“孙悟空”的所有列表项,如果不需要过滤可以调用clearTextFilter()方法。ArrayAdapter的Filter类动作定义见上一篇文章最后贴出的代码


        另外,代码里调用了filter(CharSequence)和filter(CharSequence, FilterListener)两个方法,这两个方法是在抽象类Filter中实现的,Filter抽象类的源码在下面贴出来作为参考:

/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.widget;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.util.Log;/** * <p>A filter constrains data with a filtering pattern.</p> * * <p>Filters are usually created by {@link android.widget.Filterable} * classes.</p> * * <p>Filtering operations performed by calling {@link #filter(CharSequence)} or * {@link #filter(CharSequence, android.widget.Filter.FilterListener)} are * performed asynchronously. When these methods are called, a filtering request * is posted in a request queue and processed later. Any call to one of these * methods will cancel any previous non-executed filtering request.</p> * * @see android.widget.Filterable */public abstract class Filter {    private static final String LOG_TAG = "Filter";        private static final String THREAD_NAME = "Filter";    private static final int FILTER_TOKEN = 0xD0D0F00D;    private static final int FINISH_TOKEN = 0xDEADBEEF;    private Handler mThreadHandler;    private Handler mResultHandler;    private Delayer mDelayer;    private final Object mLock = new Object();    /**     * <p>Creates a new asynchronous filter.</p>     */    public Filter() {        mResultHandler = new ResultsHandler();    }    /**     * Provide an interface that decides how long to delay the message for a given query.  Useful     * for heuristics such as posting a delay for the delete key to avoid doing any work while the     * user holds down the delete key.     *     * @param delayer The delayer.     * @hide     */    public void setDelayer(Delayer delayer) {        synchronized (mLock) {            mDelayer = delayer;        }    }    /**     * <p>Starts an asynchronous filtering operation. Calling this method     * cancels all previous non-executed filtering requests and posts a new     * filtering request that will be executed later.</p>     *     * @param constraint the constraint used to filter the data     *     * @see #filter(CharSequence, android.widget.Filter.FilterListener)     */    public final void filter(CharSequence constraint) {        filter(constraint, null);    }    /**     * <p>Starts an asynchronous filtering operation. Calling this method     * cancels all previous non-executed filtering requests and posts a new     * filtering request that will be executed later.</p>     *     * <p>Upon completion, the listener is notified.</p>     *     * @param constraint the constraint used to filter the data     * @param listener a listener notified upon completion of the operation     *     * @see #filter(CharSequence)     * @see #performFiltering(CharSequence)     * @see #publishResults(CharSequence, android.widget.Filter.FilterResults)     */    public final void filter(CharSequence constraint, FilterListener listener) {        synchronized (mLock) {            if (mThreadHandler == null) {                HandlerThread thread = new HandlerThread(                        THREAD_NAME, android.os.Process.THREAD_PRIORITY_BACKGROUND);                thread.start();                mThreadHandler = new RequestHandler(thread.getLooper());            }            final long delay = (mDelayer == null) ? 0 : mDelayer.getPostingDelay(constraint);                        Message message = mThreadHandler.obtainMessage(FILTER_TOKEN);                RequestArguments args = new RequestArguments();            // make sure we use an immutable copy of the constraint, so that            // it doesn't change while the filter operation is in progress            args.constraint = constraint != null ? constraint.toString() : null;            args.listener = listener;            message.obj = args;                mThreadHandler.removeMessages(FILTER_TOKEN);            mThreadHandler.removeMessages(FINISH_TOKEN);            mThreadHandler.sendMessageDelayed(message, delay);        }    }    /**     * <p>Invoked in a worker thread to filter the data according to the     * constraint. Subclasses must implement this method to perform the     * filtering operation. Results computed by the filtering operation     * must be returned as a {@link android.widget.Filter.FilterResults} that     * will then be published in the UI thread through     * {@link #publishResults(CharSequence,     * android.widget.Filter.FilterResults)}.</p>     *     * <p><strong>Contract:</strong> When the constraint is null, the original     * data must be restored.</p>     *     * @param constraint the constraint used to filter the data     * @return the results of the filtering operation     *     * @see #filter(CharSequence, android.widget.Filter.FilterListener)     * @see #publishResults(CharSequence, android.widget.Filter.FilterResults)     * @see android.widget.Filter.FilterResults     */    protected abstract FilterResults performFiltering(CharSequence constraint);    /**     * <p>Invoked in the UI thread to publish the filtering results in the     * user interface. Subclasses must implement this method to display the     * results computed in {@link #performFiltering}.</p>     *     * @param constraint the constraint used to filter the data     * @param results the results of the filtering operation     *     * @see #filter(CharSequence, android.widget.Filter.FilterListener)     * @see #performFiltering(CharSequence)     * @see android.widget.Filter.FilterResults     */    protected abstract void publishResults(CharSequence constraint,            FilterResults results);    /**     * <p>Converts a value from the filtered set into a CharSequence. Subclasses     * should override this method to convert their results. The default     * implementation returns an empty String for null values or the default     * String representation of the value.</p>     *     * @param resultValue the value to convert to a CharSequence     * @return a CharSequence representing the value     */    public CharSequence convertResultToString(Object resultValue) {        return resultValue == null ? "" : resultValue.toString();    }    /**     * <p>Holds the results of a filtering operation. The results are the values     * computed by the filtering operation and the number of these values.</p>     */    protected static class FilterResults {        public FilterResults() {            // nothing to see here        }        /**         * <p>Contains all the values computed by the filtering operation.</p>         */        public Object values;        /**         * <p>Contains the number of values computed by the filtering         * operation.</p>         */        public int count;    }    /**     * <p>Listener used to receive a notification upon completion of a filtering     * operation.</p>     */    public static interface FilterListener {        /**         * <p>Notifies the end of a filtering operation.</p>         *         * @param count the number of values computed by the filter         */        public void onFilterComplete(int count);    }    /**     * <p>Worker thread handler. When a new filtering request is posted from     * {@link android.widget.Filter#filter(CharSequence, android.widget.Filter.FilterListener)},     * it is sent to this handler.</p>     */    private class RequestHandler extends Handler {        public RequestHandler(Looper looper) {            super(looper);        }                /**         * <p>Handles filtering requests by calling         * {@link Filter#performFiltering} and then sending a message         * with the results to the results handler.</p>         *         * @param msg the filtering request         */        public void handleMessage(Message msg) {            int what = msg.what;            Message message;            switch (what) {                case FILTER_TOKEN:                    RequestArguments args = (RequestArguments) msg.obj;                    try {                        args.results = performFiltering(args.constraint);                    } catch (Exception e) {                        args.results = new FilterResults();                        Log.w(LOG_TAG, "An exception occured during performFiltering()!", e);                    } finally {                        message = mResultHandler.obtainMessage(what);                        message.obj = args;                        message.sendToTarget();                    }                    synchronized (mLock) {                        if (mThreadHandler != null) {                            Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN);                            mThreadHandler.sendMessageDelayed(finishMessage, 3000);                        }                    }                    break;                case FINISH_TOKEN:                    synchronized (mLock) {                        if (mThreadHandler != null) {                            mThreadHandler.getLooper().quit();                            mThreadHandler = null;                        }                    }                    break;            }        }    }    /**     * <p>Handles the results of a filtering operation. The results are     * handled in the UI thread.</p>     */    private class ResultsHandler extends Handler {        /**         * <p>Messages received from the request handler are processed in the         * UI thread. The processing involves calling         * {@link Filter#publishResults(CharSequence,         * android.widget.Filter.FilterResults)}         * to post the results back in the UI and then notifying the listener,         * if any.</p>          *         * @param msg the filtering results         */        @Override        public void handleMessage(Message msg) {            RequestArguments args = (RequestArguments) msg.obj;            publishResults(args.constraint, args.results);            if (args.listener != null) {                int count = args.results != null ? args.results.count : -1;                args.listener.onFilterComplete(count);            }        }    }    /**     * <p>Holds the arguments of a filtering request as well as the results     * of the request.</p>     */    private static class RequestArguments {        /**         * <p>The constraint used to filter the data.</p>         */        CharSequence constraint;        /**         * <p>The listener to notify upon completion. Can be null.</p>         */        FilterListener listener;        /**         * <p>The results of the filtering operation.</p>         */        FilterResults results;    }    /**     * @hide     */    public interface Delayer {        /**         * @param constraint The constraint passed to {@link Filter#filter(CharSequence)}         * @return The delay that should be used for         *         {@link Handler#sendMessageDelayed(android.os.Message, long)}         */        long getPostingDelay(CharSequence constraint);    }}


0 0