Handler 原理

434 阅读2分钟
  • 参考地址
  • handler 线程通信的简单总结
    • 1、在线程1中创建handler 对象;
    • 2、在线程2中使用handler对象发送message,然后再线程1中根据Message去执行相关逻辑,从而达到2个线程通讯;
  • 原理:
    • 1、在线程2中,handler使用sendMessage() 会将 message 放入线程1的 MessageQueue中,messageQueue 是一个链表;
          // 步骤2:创建消息对象
          Message msg = Message.obtain(); // 实例化消息对象
          msg.what = 1; // 消息标识
          msg.obj = "AA"; // 消息内容存放
      
    • 2、在线程1中,looper 对象会开启一个死循环,不断的从该线程的MessageQueue中取出message,然后通过dispatchMessage(msg)分发出去;
      final MessageQueue queue = me.mQueue;
      // 获取Looper实例中的消息队列对象(MessageQueue)
      // 2. 消息循环(通过for循环)
      for (;;) {
          // 2.1 从消息队列中取出消息,  若取出的消息为空,则线程阻塞
          Message msg = queue.next(); 
          if (msg == null) {
              return;
          }
          // 2.2 派发消息到对应的Handler
          msg.target.dispatchMessage(msg);
          // 把消息Message派发给消息对象msg的target属性
          // target属性实际是1个handler对象
      
          // 3. 释放消息占据的资源
          msg.recycle();
      }
      
    • 3、Looper 会和线程绑定,所以一个线程可以有多个handler,但是只能有一个Looper和一个MessageQueue。
  • 补充1:

    如下列方式创建Handler对象,其会持有一个外部类对象(即当前的Activity)。 然而当handler在子线程调用时,如果还未执行时,当前activity被关闭,那么由于该子线程还持有handler引用,会导致activity无法被垃圾回收机制(GC)发现回收,从而导致内存泄漏
    避免方法:
    1、可以使用弱引用的方式创建Handler, GC检查回收时会忽略弱引用;
    2、在Activity 的onDestory()中清除handler的所有message,handler.removeCallbacksAndMessages(null);

  • 补充2:关于handler.sendMessage()后msg如何回到自己的handler.handleMessage()中的进一步说明:
    • 1、在handler.sendMessage()-->sendMessageDelayed()-->sendMessageAtTime()-->enqueueMessage();在enqueueMessage方法中会有如下代码,此时将handler对象赋值给msg.target;
       msg.target = this;
      
    • 2、当在Looper中分发msg 时,会有msg.target.dispatchMessage(msg);所以会把handler分发给其对应的handler;
  • handler message延时原理

    handler.postDelayed(Runnable, time) --> sendMessageDelayed(..,time) --> ... -->最终 enqueueMessage(Message msg, long when) 方法;
    1、在enqueueMessage中会将延时时长放在msg上(msg.when = when;)并加入messageQueue中;
    2、然后在Loop.loop()开始循环的时候判断如果这个Message是否有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞。例如当前msg存在延时,且延时时间还没到,则提前获取下一个msg;