android里Filter的研究

一、概述:
     过滤器通过过滤模式来约束数据,过滤操作是通过调用filter(CharSequence)或者filter(CharSequence, android.widget.Filter.FilterListener)这些异步方法来完成的。以上方法一旦被调用,过滤请求就会被递交到请求队列中等待处理,同时该操作会取消那些之前递交的但是还没有被处理的请求。
     其工作过程可以简单理解为:有一个工作队列在处理任务,但每次只能处理一个任务。每次提交一个任务的时候,如果工作队列中没有正在执行的任务,则立马执行该任务。如果有执行的任务,则该任务等待。如果队列中有正在执行的任务,并且有等待的任务,则取消所有等待的任务,把该任务放入等待的过程中。所以在任何时候,最多只能有一个任务在执行,一个任务在等待。

二、主要方法:    
     public void final filter(CharSequence constraint, FilterListener listener);
     执行一个异步的过滤操作请求。

     protected abstract FilterResults  performFiltering(CharSequence constraint);
     根据约束条件调用一个工作线程来过滤数据,子类必须实现该方法来执行过滤操作。过滤结果以Filter.FilterResults的形式返回,然后在UI线程中通过publishResults(CharSequence, android.widget.Filter.FilterResults)方法来发布。      

     protected abstract void  publishResults(CharSequence constraint, FilterResults results);
    通过调用UI线程在用户界面发布过滤结果。

三、实现原理:
     在一个新开的工作线程里执行过滤的操作,过滤的结果在UI线程里publish。

     1.在Filter类里使用了2个Handler: RequestHandler是用来处理过滤操作的, ResultHandler是用来发布过滤结果的。
            private Handler mThreadHandler;
            private Handler mResultHandler;    
            
            public Filter() {
                 mResultHandler = new ResultHandler();
            }
            可见,ResultHandler在构造方法里创建,一般说来是与UI线程进行绑定的,最后过滤出结果后,publishResults是通过ResultHandler来进行分发消息的,所以最后的回调过程是在UI线程执行的,这里实现的很巧妙,可以学习之。
            疑问:如果Filter类是在一个子线程里进行创建的,则在publishResults时,就不是在UI线程里执行了?实际结果是,如果在子线程里 new一个Filter对象,则会直接报错,原因是子线程里还没有构造Looper对象,需要在new Handler()之前调用Looper.prepare()方法。
     
     2.filter请求流程。
          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);
             }
          }     
          可以看到,在这里才会创建一个HandlerThread对象,这是一个子线程,随后会创建一个RequestHandler,该Handler会与该子线程绑定。以后所有的过滤请求,都通过RequestHandler进行分发,所有的过滤操作,都会在子线程中执行。
          在发起本次请求之前,会通过RequestHandler取消掉所有还未执行的消息。
     
          再看一下RequestHandler的内部实现,
          
               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();
                    }
                     //在这里可以看到,会调用performFiltering()方法进行过滤,接着会通过ResultHandler进行结果发布。

                    synchronized (mLock) {
                        if (mThreadHandler != null) {
                            Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN);
                            mThreadHandler.sendMessageDelayed(finishMessage, 3000);
                        }
                    }
                    / /在所有操作执行完毕后,会延迟3秒发送一个结束的消息,该消息会终止掉HandlerThread线程里的消息循环。这个地方很巧妙:1.如果连续的发起过滤请求,则会一直使用之前创建的HandlerThread线程来处理过滤操作,不会频繁的创建线程,过多的损耗性能;2.如果长时间没有过滤请求,比如超过3s后,则会终止点该线程,因为该线程实际上是个空闲的线程,可以终止掉,同样的减少性能损耗。注意要加锁操作。

                    break;
                case FINISH_TOKEN:            //这里处理终止线程的操作
                    synchronized (mLock) {
                        if (mThreadHandler != null) {
                             mThreadHandler.getLooper().quit();
                            mThreadHandler = null;
                        }
                    }
                    break;

四、总结:
     1.巧妙的使用了HandlerThread来创建一个带Looper的Thread。
     2.通过与不同线程绑定的Handler,来实现异步的过滤查询操作。
     3.类似AutoCompleteTextView的实现,通过Filter来实现。
     4.参考Filter的实现方式,可以在需要频繁异步查询的地方,采用同样的设计方法。比如输入框里的联网自动提示功能。
     5.AsyncQueryHandler实现原理与之类似,都是采用了HandlerThread,使用一个工作线程来处理事情。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android编译过程中,filter(过滤)是一个常用的操作,用于选择要编译的特定模块或文件。通过使用filter,可以减少编译时间和生成的输出大小。 要在Android编译中使用filter,可以按照以下步骤进行操作: 1. 打开终端或命令提示符,并进入Android源码根目录。 2. 使用lunch命令选择要编译的目标设备。例如,使用以下命令选择编译Pixel 3设备: ``` $ lunch aosp_blueline-userdebug ``` 3. 运行make命令来开始编译过程。在make命令中,可以使用以下参数来指定filter: - `MODULES-INCLUDE=<模块1,模块2>`:指定要包含的模块列表。 - `MODULES-EXCLUDE=<模块1,模块2>`:指定要排除的模块列表。 - `TARGET_FILES=<文件1,文件2>`:指定要编译的特定文件列表。 例如,以下命令将只编译名为"Module1"和"Module2"的模块: ``` $ make MODULES-INCLUDE=Module1,Module2 ``` 或者,以下命令将编译除了名为"Module3"之外的所有模块: ``` $ make MODULES-EXCLUDE=Module3 ``` 还可以使用通配符来匹配多个模块或文件。例如,以下命令将编译所有以"Module_"开头的模块: ``` $ make MODULES-INCLUDE=Module_* ``` 注意:filter参数的具体用法可能因不同的Android版本和构建系统而有所差异。请根据你使用的具体情况进行适当的调整。 通过使用filter,你可以选择性地编译Android源码中的模块或文件,以满足你的特定需求。这可以提高编译效率并减少生成的输出大小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值