要理解Handler首先要理解Looper,Handler,Thread这几个的关系,然后再是消息队列,消息本身,消息传递之间的相互协作关系
Looper class
Looper和ThreadLocal类关系图
Looper初始化
在线程中初始化Looper如下
class HandlerThread(private val context: Context): Runnable{
private lateinit var mHandler: Handler
fun getHandler() = mHandler
override fun run() {
Looper.prepare()
mHandler = ThreadHandler(Looper.myLooper()!!, context)
Looper.loop()
}
}当执行到Looper.loop()后,该线程就进入了死循环,不过底层是Linux管道机制,不会一直占用CPU,一旦Handler收到新消息,looper消息循环队列就会激活线程,处理消息
初始化时序图
总结:
Looper包含了MeesageQueue,Thread,ThreadLocal
ThreadLocal更像是一个Helper类,通过set函数将looper保存到当前线程Thread.threadLocals中,ThreadLocal为key,looper为value
ThreadLocalMap可以理解为定制版的HashMap,使用了线性探测法来解决哈希冲突
Handler和Looper,Message以及消息队列关系
Looper初始化时会初始化一个mQueue消息队列
Looper.loop函数会开启一个死循环,一直读取mQueue里边的数据
Handler初始化必须传入Looper,如果没有会从当前线程获取绑定的looper, Looper.prepare的时候绑定looper
Handler初始化时从Looper获取绑定的mQueue
Handler发送消息会将msg添加到队尾
MessageQueue
MessageQueue维护了一个单向线性链表,链表的结点就是Message对象,其next字段指向链表下一个结点, Looper.loop函数会一直从消息队首获取消息,如果没有消息就会进入阻塞
时序图
MessageQueue取出消息流程
Handler处理消息跨线程
Handler初始化时从Looper获取到了mQueue消息队列
同一个进程中主线程和子线程共享变量Handler,Handler持有的mQueue也是共享的,当在子线程通过handler发送消息时,消息通过MessageQueue进入队列,其enqueueMessage方法代码块,加了synchronized关键字,一个多线程安全的函数,子线程的msg就加入到了共享变量消息队列中
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}在主线程中,Looper在不断的取出消息,然后分发给handler处理,主线程中的Handler就收到消息开始处理,完成一次消息的跨进程
简单理解为主线程和子线程同时操作MessageQueue实现跨线程msg的传递
参考资料
[1]. Android Handler机制:epoll的高效等待与唤Handler 机制是 Android 主线程能够流畅 - 掘金