美文网首页Android
Android Handler

Android Handler

作者: 微风LE | 来源:发表于2019-02-26 17:53 被阅读0次

    Handler 作用

    Android 中的Handler 主要用于主线程与子线程之间的通信,也就是处理异步消息。
    简单理解来说主线程无法处理耗时任务,不然就会阻塞线程,那么就会用子线程来异步处理耗时工作,而子线程无法直接更新UI界面,所以需要handler来传递消息给主线程,让主线程完成UI界面的更新工作。

    概念:MessageQueue和Looper

    MessageQueue用来保存子线程从Handler所发送未处理的消息,就是个消息队列,负责消息的入列出列。
    Looper依次取出MessageQueue中的消息传递给主线程响应处理。

    Handler原理是什么?

    一、Handler封装了消息的发送 (主要包括消息发送给谁)
    Looper
    1、内部包含一个消息对列,也就是MessageQueue,所有的handler发送的消息都走向这个消息对列。
    2、Loopler.looper方法,就是一个死循环,不断地从MessageQueue取消息,如果有消息就处理消息,没有消息就阻塞
    二、MessageQueue,就是一个消息对列,可以添加消息,并处理消息
    三、handler也很简单,内部会跟Looper进行关联,也就是说在handler的内部可以找到Looper,找到Looper也就找到了MessageQueue,在handler中发送消息,其实就是向MessageQueue队列中发送消息
    总结:handler负责发送消息,Looper负责接收handler发送的消息,并直接把消息回传给handler自己。MessageQueue就是一个存储消息的容器

    用法:Handler基本用法

    android.os.Handler handler = new Handler(){
      @Override
      public void handleMessage(final Message msg) {
        //这里接受并处理消息
      }
    };
    //发送消息
    handler.sendMessage(message);
    handler.post(runnable);
    

    实例化一个 Handler 重写 handleMessage 方法 ,然后在需要的时候调用它的 send 以及 post 等方法就可以了,非常简单易用,并且支持延时消息操作。

    Handler 与 Looper 的关联
    一般在实例化 Handler 的时候, Handler 会去检查当前线程的 Looper 是否存在,如果不存在则会报异常,在创建 Handler 之前一定需要先创建 Looper 。

    class LooperThread extends Thread {
        public Handler mHandler;
        public void run() {
            Looper.prepare();
            mHandler = new Handler() {
                public void handleMessage(Message msg) {
                    // process incoming messages here
                }
            };
            Looper.loop();
        }
    }
    

    Looper.prepare() :
    也就是说 Handler 跟线程的关联是靠 Looper 来实现的。

    Message 的对象

    message.what=1;//what属性
    message.arg1=i;//arg属性
    message.obj="消息内容:";//obj属性
    handler.sendMessage(message);
     if (msg.what==1)//识别判断消息
       {
            //todo something
        }
    

    Message 的存储与管理
    Handler 提供了一些列的方法让我们来发送消息,如 send()系列 post()系列 。
    以 sendEmptyMessage(int) 方法为例:

    //Handler
    sendEmptyMessage(int)
      -> sendEmptyMessageDelayed(int,int)
        -> sendMessageAtTime(Message,long)
          -> enqueueMessage(MessageQueue,Message,long)
                -> queue.enqueueMessage(Message, long);
    

    最终都会走到 Message.enqueueMessage(Message,long) 方法。
    上面我们可以看到消息的管理者是 MessageQueue
    MessageQueue用来保存子线程从Handler所发送未处理的消息,就是个消息队列,负责消息的入列出列。

    Handler 引起的内存泄漏原因

    Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄漏。
    这个泄漏是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,
    使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄漏。
    

    解决方案

    将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息。
    示例:

    private static class SafeHandler extends Handler {
    
        private WeakReference<HandlerActivity> ref;
    
        public SafeHandler(HandlerActivity activity) {
            this.ref = new WeakReference(activity);
        }
    
        @Override
        public void handleMessage(final Message msg) {
            HandlerActivity activity = ref.get();
            if (activity != null) {
                activity.handleMessage(msg);
            }
        }
    }
    

    并且再在 Activity.onDestroy() 前移除消息,加一层保障:

    @Override
    protected void onDestroy() {
      safeHandler.removeCallbacksAndMessages(null);
      super.onDestroy();
    }
    

    这样双重处理,就能避免内存泄漏。
    注意:单纯的在 onDestroy 移除消息并不保险,因为特定情况下 onDestroy 并不一定执行。

    常见Toast crash

    当我们尝试在子线程里直接去弹 Toast 的时候,会发生crash :

    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    

    本质上是因为 Toast 的实现依赖于 Handler,按子线程使用 Handler 的要求修改即可,同理的还有 Dialog。
    正确示例代码如下:

    new Thread(new Runnable() {
      @Override
      public void run() {
        Looper.prepare();
        Toast.makeText(HandlerActivity.this, "正常Toast啦!", Toast.LENGTH_SHORT).show();
        Looper.loop();
      }
    });
    

    以上粗略总结也是日常常识以及在学习中参考大佬们的总结。不喜匆喷,欢迎指正。_
    ---by mars_chu 啥都不会的楚楚

    相关文章

      网友评论

        本文标题:Android Handler

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