要理解Handler首先要理解Looper,Handler,Thread这几个的关系,然后再是消息队列,消息本身,消息传递之间的相互协作关系

Looper class

Looper和ThreadLocal类关系图

classDiagram class Looper{ ~sThreadLocal: ThreadLocal ~mThread: Thread ~mQueue: MessageQueue +prepare() +myLooper(): this } class ThreadLocal{ +set(looper) +get():looper ~createMap() } class ThreadLocalMap{ -table -size +set(sThreadLocal,looper) +getEntry(looper) } class Thread{ ~threadLocals:ThreadLocalMap +currentThread():this } Looper o-- Thread Thread o-- ThreadLocalMap Looper o-- ThreadLocal ThreadLocal --> Thread ThreadLocal o-- ThreadLocalMap

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消息循环队列就会激活线程,处理消息

初始化时序图

sequenceDiagram Looper ->> Looper:prepare() Looper -->> Looper: Looper() note over Looper,ThreadLocal:初始化消息队列mQueue和mThread Looper ->> ThreadLocal:set(this) ThreadLocal ->> Thread:curentThread() Thread -->> ThreadLocal: return thread ThreadLocal ->> Thread:getMap(thread) note over ThreadLocal,Thread:返回Thread关联的Map Thread -->> ThreadLocal:Thread.threadLocals alt map == null ThreadLocal -->> ThreadLocal: createMap() note over ThreadLocal,Thread:创建map赋予thread ThreadLocal ->> Thread:threadLocals = map else map != null ThreadLocal ->> ThreadLocalMap: set(this,looper) end

总结:

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函数会一直从消息队首获取消息,如果没有消息就会进入阻塞

时序图

sequenceDiagram Looper ->> Looper: loop() loop 死循环 Looper -->> Looper:loopOnce Looper ->> MessageQueue: next() loop 遍历链表 MessageQueue -->> MessageQueue: next end end

MessageQueue取出消息流程

flowchart TB Z(开始循环) Z --> X X[阻塞唤醒nativePollOnce] A(队首第一个MSG) B{是否是屏障消息<br>target==null?} C(查找下一个MSG) D{是否是异步消息} X --> A A -->B B --是-->C C -->D D --否--> C E{消息是否为空} D --是--> E B --否-->E F{消息是否到了执行时间} E --否--> F E --是--> X F --是-->G G(将MSG移除链表) G --> H(标记为inUse) H-->I(返回MSG) F --否-->X I --> END((结束))

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 主线程能够流畅 - 掘金

春风花气馥,秋月寒江湛