0
点赞
收藏
分享

微信扫一扫

Handler机制

半夜放水 2021-10-09 阅读 115
随笔

每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。

Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,

如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。

使用消息池的好处是:消息不被使用时,并不作为垃圾回收,

而是放入消息池,可供下次Handler创建消息时使用。

消息池提高了消息对象的复用,减少系统垃圾回收的次数。

UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。

使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。

Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

Handler、Looper、MessageQueue的初始化流程如图所示:

Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,

子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。

UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,

通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。



主要分为三个步骤:

* Looper.prepare();

* looper.loop();

* (1)new Handler();这一步的操作

* 通过Looper类中的ThreadLocal从主线程获取到了Looper对象

* 然后通过Looper对象获取到MessageQueue的引用

*

* (2)Handler.sendMessage();这一步的操作

* 找到MessageQueue对象

* 然后msg.target=this,将handler对象成为msg的一个成员变量‘

* 最后把msg添加到MessageQueue

*

* (3)Looper的loop();这一步的操作

* 找到MessageQueue

* 开启死循环,遍历消息池MessageQueue

* 当获取到msg的时候,通msg.target.dispatchMessage(msg);调用handler的dispatchMessage();

* dispatchMessage()中调用handleMessage(),该方法在子类实现。

*

* 找到消息池,从消息池中取msg,死循环取,

* 这里的死循环为什么不会造成卡顿?  因为这里的死循环会释放CPU资源,queue里边有消息,会向下执行,并且Android系统就是基于这种消息机制(每隔16ms刷新一次屏幕的消息也是需要在这里进行处理)。



ThreadLocal与线程是一一对应的。Thread类中,ThreadLocal作为成员变量来使用。ThreadLocal只是ThreadLocalMap的外部包装类,实现了get   set 方法。而ThreadLocalMap是一个由Entry内部类组成的数组,Entry继承自弱引用,弱引用中存放的是当前ThreadLocal对象,Entry的value存储的是当前线程所要存储的对象,value作为Entry的成员变量。
ThreadLocal会被问道内存泄漏的问题,从上面分析可知,ThreadLocal里面的Entry对象存储的是ThreadLocal弱引用,而value直接作为Entry的强引用,因此在用到了ThreadLocal的地方,为了防止内存泄漏,手动调用remove方法。

handler.sendMessage()与handler.postMessage()的区别?

这个面试题主要考察对于handler源码的熟悉程度,

sendMessage()的主要流程:
sendMessageDelayed()---->sendMessageAtTime---->enqueueMessage---->queue.enqueueMessage( ),msg.when属性设置----->looper.loop()轮询器取出msg,根据msg.when,确定执行顺序------------------------------------------>msg.target.dispatchMessage(msg);----->handler.dispatchMessage----->检查msg.callback是否为null,为空则走handleMessage()回调。

post(Runnable  r)的主要流程:
post---->sendMessageDelayed(getPostMessage(r), 0);----->getPostMessage(r),----->Message m = Message.obtain();m.callback = r;给msg设置callback属性值为传递进来的runnable------>sendMessageAtTime---------->enqueueMessage---->queue.enqueueMessage( ),msg.when属性设置----->looper.loop()轮询器取出msg,根据msg.when,确定执行顺序------->msg.target.dispatchMessage(msg);----->handler.dispatchMessage----->检查msg.callback是否为null,不为空则走handleCallback()回调。----->message.callback.run();手动调用这个runnable的run方法。

下面是dispatchMessage的源码:
public void dispatchMessage(@NonNull Message msg) {

        if (msg.callback !=null) {
              handleCallback(msg);
         }else {
             if (mCallback !=null) {
                  if (mCallback.handleMessage(msg)) {
                       return;
                   }
             }
          handleMessage(msg);
          }
}

handleCallback方法源码:

private static void handleCallback(Message message) {
        message.callback.run();
}

举报

相关推荐

0 条评论