Handler機制解析

檸檬茶就是力量發表於2019-07-23

分析一下Handler原始碼以及一些核心部分的程式碼

Handler 原理:

首先sendMessage()以及 sendMessageDelayed()最後呼叫的都是 sendMessageDelayed(),接著開始總體流程
遍歷連結串列: 首先判斷連結串列裡有沒有message,如果裡面是空的或者傳入的msg執行的時間比頭message要早,則把msg放到連結串列的頭部,( 比如send兩次message,先執行的有延時,後執行的沒延時,這個時候就要把後執行的message放到最前面) 接著遍歷連結串列,根據執行的事件去調整message的位置:

第一次新增資料到佇列中,或者當前 msg 的時間小於 mMessages 的時間

// p為佇列中頭部msg
if (p == null || when == 0 || when < p.when) {

        // New head, wake up the event queue if blocked.

        // 把當前 msg 新增到連結串列的第一個

        msg.next = p;

        mMessages = msg;

        needWake = mBlocked;

} else {

        // 不是第一次新增資料,並且 msg 的時間 大於 mMessages(頭指標) 的時間

        // Inserted within the middle of the queue.  Usually we don't have to wake

        // up the event queue unless there is a barrier at the head of the queue

        // and the message is the earliest asynchronous message in the queue.

        needWake = mBlocked && p.target == null && msg.isAsynchronous();

        Message prev;

        for (;;) {

        // 不斷的遍歷找到合適的位置

        prev = p;

        p = p.next;

        if (p == null || when < p.when) {     // 根據執行時間判斷應該插到哪個位置    

        break;

        }

        if (needWake && p.isAsynchronous()) {

        needWake = false;

        }

        }

        // 把當前 msg 插入到列表中

        msg.next = p; // invariant: p == prev.next

        prev.next = msg;

}

複製程式碼

Looper

Looper是通過不斷迴圈去獲取message的,要使用handler,子執行緒中必須呼叫looper.prepare()以及 looper.loop()。主執行緒中預設有一個looper,ActivityThread中系統已經初始化了一個looper,下面是具體邏輯程式碼
public static void loop() {

    final Looper me = myLooper();

    final MessageQueue queue = me.mQueue;

    // 一個死迴圈

    for (;;) {

        // 不斷的從訊息佇列裡面取訊息

        Message msg = queue.next(); // might block

        if (msg == null) {

            // No message indicates that the message queue is quitting.

            return;

        }

        try {

            // 通過 target 去 dispatchMessage 而 target 就是繫結的 Handler
            // 到這裡也就完成了訊息的傳遞流程

            msg.target.dispatchMessage(msg);

        } finally {

            // 訊息回收迴圈利用

            msg.recycleUnchecked();

        }

    }

}
複製程式碼

在這裡loop的死迴圈涉及到pipe知識就不深入探討,如下圖

image.gif

image.png

相關文章