美文网首页
Android Handler 消息机制

Android Handler 消息机制

作者: xulj100 | 来源:发表于2019-07-08 20:08 被阅读0次

    1、先来了解下下面的几个重要的组件:

    • Handler:收发消息工具。
    • Message:Hander接收和处理消息对象。
    • Looper:每一个线程拥有一个looper,创建消息队列,循环取队列里的消息进行分发。
    • MessageQueue:消息队列,采用先进先出的方法俩管理Message对象,程序创建Looper对象 时,会在它的构造器中创建MessageQueue对象。
    image.png

    2、在子线程中创建Handler:
    方法1:在new Handler()前后加上 Looper.prepare()和 Looper.loop()

    //子线程创建handler,需要创建looper
      new Thread(new Runnable() {
         @Override
          public void run() {
              Looper.prepare();
              @SuppressLint("HandlerLeak")
              Handler handler = new Handler() {
               @Override
               public void handleMessage(Message msg) {
                 super.handleMessage(msg);
                        }
                    };
                  Looper.loop();
                }
            }).start();  
    

    方法二:传入主线程的Looper来实现

     //将主线程的looper传进来
    new Thread(new Runnable() {
      @Override
      public void run() {
      Handler handler = new Handler(Looper.getMainLooper()) {
      @Override
      public void handleMessage(Message msg) {
        super.handleMessage(msg);
                }
            };
        }
     }).start();
    

    3、handler之内存泄漏:
    造成泄露原因:

    • Handler 的生命周期与Activity 不一致:当Android应用启动的时候,会先创建一个UI主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。当在主线程中初始化Handler时,该Handler和Looper的消息队列关联(没有关联会报错的)。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
    • handler 引用 Activity 阻止了GC对Acivity的回收在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。如果外部类是Activity,则会引起Activity泄露 。当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

    4、如何避免内存泄露:

    • 通过程序逻辑来进行保护
      在Activity销毁时,将消息从消息队列中移除
      removeMessages(int what)
      removeCallbacks(Runnable r)
      removeCallbacksAndMessages(null);
    • 将Handler声明为静态类 (见如下代码)
     private static class ActivityHandler extends Handler {
            private final WeakReference<AsyncActivity> mActivity;
    
            public ActivityHandler(AsyncActivity activity) {
                this.mActivity = new WeakReference(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                if (this.mActivity != null) {
                    AsyncActivity activity = this.mActivity.get();
                    if (activity != null && !activity.isFinishing()) {
                        activity.handleMessage(msg);
                    }
                }
            }
        }
    
        public void handleMessage(Message msg) {
        }
    

    5、Looper能创建多个实例嘛?能自己创建Looper实例嘛?
    Looper只能创建一个实例,可以自己调用Looper.prepare()方法创建实例。
    先来看Looper的prepare()方法,调用多次prepare方法创建实例,会抛出异常。

      public static void prepare() {
            prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    

    ThreadLocal类的特性:ThreadLocal是线程内部的数据存储类,当使用ThreadLocal维护变量的时候,它会为每个使用该变量的线程提供一个独立的变量副本,这个变量副本是该线程独有,不受其他线程影响。
    Looper的主要作用是与当前线程形成一种绑定的关系,同时创建一个MessageQueue,这样保证一个线程只能持有一个Looper和MessageQueue,同时Looper使得MessageQueue循环起来。

    6、handler,asyncTask有什么区别?
    Android的AsyncTask比Handler更轻量级一些(只是代码上轻量一些,而实际上要比handler更耗资源),适用于简单的异步处理。
    AsyncTask的重写方法:

    • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用+ publicProgress(Progress…)来更新任务的进度。
    • onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
    • onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
    • onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
    • onCancelled() 用户调用取消时,要做的操作。

    使用AsyncTask类,以下是几条必须遵守的准则:

    • Task的实例必须在UI thread中创建;
    • execute方法必须在UI thread中调用;
    • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
    • 该task只能被执行一次,否则多次调用时将会出现异常;

    AsyncTask优缺点
    优点:简单,快捷, 过程可控。
    缺点:在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来,最大并发数不超过5。
    Handler优缺点:
    优点:结构清晰,功能定义明确,对于多个后台任务时,简单,清晰。
    缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)。

    相关文章

      网友评论

          本文标题:Android Handler 消息机制

          本文链接:https://www.haomeiwen.com/subject/ruaahctx.html