細(xì)致一點(diǎn)地看看 Handler 和它的伙伴們

Handler 對(duì)于 Android 開發(fā)來說簡(jiǎn)直就是家常便飯,它的原理自然都很熟悉,這篇文章不會(huì)宏觀地去介紹它的原理,而是細(xì)節(jié)深入到各個(gè)組成。

目錄

關(guān)系

開始深入細(xì)節(jié)的時(shí)候,我們可以先復(fù)習(xí)下 Handler 、Looper 和 MessageQueue 三者的關(guān)系。

  1. Handler 必須在 Looper.prepare() 之后才能創(chuàng)建使用
  2. Looper 與當(dāng)前線程關(guān)聯(lián),并且管理著一個(gè) MessageQueue
  3. Message 是實(shí)現(xiàn) Parcelable 接口的類
  4. 以一個(gè)線程為基準(zhǔn),他們的數(shù)量級(jí)關(guān)系是:
    Handler(N) : Looper(1) : MessageQueue(1) : Thread(1)

他們的調(diào)用關(guān)系可以參考這張圖:


分析

0x01
public Handler(Callback callback, boolean async) {
    // 代碼省略

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

從 Handler 默認(rèn)的構(gòu)造函數(shù)我們可以看到,Handler 內(nèi)部會(huì)通過 Looper.myLooper() 來獲取 Looper 對(duì)象,從而與之關(guān)聯(lián)。

0x02

我們之前已經(jīng)知道 Looper 管理著消息隊(duì)列,從這里深入進(jìn)去看看是如何跟 MessageQueue 建立聯(lián)系。

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

public static void prepare() {
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

Looper.myLooper() 里我們看到,Looper 是通過 sThreadLocal.get() 來獲取,那么我們又是何時(shí)將 Looper 設(shè)置給 sThreadLocal 的呢?答案就在 prepare() 方法里。
我們看到 sThreadLocal.set(new Looper(quitAllowed)); 實(shí)例化了一個(gè) Looper 對(duì)象給 sThreadLocal 并且一個(gè)線程只有一個(gè) Looper 。

同時(shí)我也貼出了 prepareMainLooper() 方法,根據(jù)名字大家都可以猜到,這個(gè)方法就是在 Android 主線程(UI)線程調(diào)用的方法,而在這個(gè)方法里也調(diào)用了 prepare(false) 我們看到這里傳入的是 false ,表明主線程這里的 Looper 是無法執(zhí)行 quit() 方法。
我在這里貼出 ActivityThread 的 Main() 方法的部分代碼,這也是我們程序的入口:

public static void main(String[] args) {
    // 代碼省略

    Looper.prepareMainLooper(); // 創(chuàng)建消息循環(huán) Looper

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler(); // UI 線程的 Handler
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    Looper.loop(); // 執(zhí)行消息循環(huán)

}

在這里我們更清楚了為什么可以直接在主線程創(chuàng)建 Handler ,而不會(huì)發(fā)生異常。

以上,我們明白了 Looper 是通過 prepare() 方法與線程建立聯(lián)系,同時(shí)不同線程是無法訪問對(duì)方的消息隊(duì)列。

為什么 Handler 要在主線程創(chuàng)建才能更新 UI 呢?

因?yàn)?Handler 要與主線程的消息隊(duì)列關(guān)聯(lián)上,這樣 handleMessage() 才會(huì)執(zhí)行在 UI 線程。

0x03

Looper 的核心其實(shí)是它循環(huán)取出消息的代碼:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // 死循環(huán)
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        /// Handler msg.target
        msg.target.dispatchMessage(msg); // 派發(fā)消息

        // 代碼省略

        msg.recycleUnchecked();
    }
}

從上面代碼我們可以看到,Looper 在 loop() 方法里建立了一個(gè)死循環(huán),通過消息隊(duì)列里不斷的取出消息,交給 Handler 去處理。

這個(gè)時(shí)候你可能會(huì)有一個(gè)問題:

Android 中為什么主線程不會(huì)因?yàn)?Looper.loop() 里的死循環(huán)卡死?

我比較推薦 Gityuan 的回答

回到我們這里,在循環(huán)中是通過 msg.target.dispatchMessage(msg); 派發(fā)消息。其中 msg 是 Message 類型,簡(jiǎn)單看看它的成員:

public final class Message implements Parcelable {
    Handler target;
    Runnable callback;
    Message next;

    public Object obj;
    public int arg1;
    public int arg2;

    // 代碼省略
}

可以知道消息隊(duì)列是鏈表實(shí)現(xiàn)的,并且 target 是 Handler 類型。

現(xiàn)在就可以連通了,通過 Handler 將 Message 投遞給消息隊(duì)列(鏈表),Looper.loop() 循環(huán)從消息隊(duì)列里取出消息,又將消息分發(fā)給 Handler 去處理。通過這個(gè) target 我們也可以知道一個(gè)小細(xì)節(jié),Handler 只能處理自己所發(fā)出的消息。

0x04

理解清楚之后我們跟著順序,看看 Handler 是如何處理和分發(fā)消息的。

// 處理消息方法,交給子類復(fù)寫
public void handleMessage(Message msg) {
}

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

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

我們看到 dispatchMessage() 只是一個(gè)分發(fā)方法,如果 Runnable 類型的 callback 為空,則執(zhí)行 handleMessage(msg) 處理信息,該方法為空,是交給子類進(jìn)行復(fù)寫,并且執(zhí)行線程是在 Handler 所創(chuàng)建的線程。
如果 callback 不為空,則會(huì)執(zhí)行 handleCallback(msg) 來處理信息,該方法會(huì)調(diào)用 callback 的 run() 方法。

其實(shí)說簡(jiǎn)單一點(diǎn),就是 Handler 的兩種分發(fā)類型。
一種是 post(r) 另一種是 sendMessage(msg)

我們具體看看這兩個(gè)方法:

public final boolean post(Runnable r){
   return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r){
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 與當(dāng)前 Handler 綁定
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

做了一個(gè)導(dǎo)圖,方便理解下:


從中我們可以看到,在 post(r) 時(shí),會(huì)將 Runnable 包裝成 Message 對(duì)象,并且賦值給 Message 的 callback 字段,最后跟 sendMessage(msg) 方法一樣將消息插入隊(duì)列。

根據(jù)代碼和導(dǎo)圖,無論是 post(r) 還是 sendMessage(msg) 都會(huì)最終調(diào)用 sendMessageAtTime(msg,time)

總結(jié)

Handler 最終將消息追加到 MessageQueue 中,而 Looper 不斷的從 MessageQueue 中讀取消息,并且調(diào)用 Handler 的 dispatchMessage 分發(fā)消息,最后交給上層處理消息。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容