每一个消息都需要被指定的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();
}