從源碼角度分析 Handler Looper MessageQueue

博客原文地址:http://jockio.github.io/2016/08/16/source-code-of-handler-and-looper/

前言

首先我們要知道,創(chuàng)建Handler之前,要先創(chuàng)建與之配套的Looper。
在主線程中,系統(tǒng)已經(jīng)初始化了一個(gè) Looper 對(duì)象,因此程序直接創(chuàng)建 Handler 對(duì)象即可,然后就可以通過 Handler 來發(fā)送、處理消息了。
在子線程中,必須自己創(chuàng)建一個(gè) Looper 對(duì)象,并啟動(dòng)它。
創(chuàng)建 Looper 對(duì)象調(diào)用它的 prepare 方法即可(prepare 方法保證每個(gè)線程最多只有一個(gè) Looper 對(duì)象),然后調(diào)用 Looper 的靜態(tài) loop 方法來啟動(dòng)它。loop 方法使用一個(gè)死循環(huán)不斷地從MessageQueue 中取消息,并將取出的消息分發(fā)給該消息對(duì)應(yīng)的 Handler 處理。至于它們具體做了哪些事,我們會(huì)在后面詳細(xì)講述。

Looper的創(chuàng)建

我們先看一下Looper的構(gòu)造函數(shù)

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

首先我們注意到該構(gòu)造方法是被private修飾的,也就是說我們無法通過new的方式來創(chuàng)建Looper。其次,我們可以從Looper的構(gòu)造方法中看出,在創(chuàng)建Looper的時(shí)候,創(chuàng)建了與之配套的MessageQueue,然后獲取了創(chuàng)建當(dāng)前Looper線程的引用。
而要想創(chuàng)建Looper,只需調(diào)用Looper.prepare();。該方法保證了一個(gè)線程只能創(chuàng)建一個(gè)與之相關(guān)聯(lián)的Looper,并且將創(chuàng)建出的Looper與當(dāng)前線程綁定起來。

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));
}

Handler的創(chuàng)建

Looper對(duì)象成功創(chuàng)建之后,我們?cè)賮砜纯碒andler。當(dāng)我們調(diào)用Handler的無參構(gòu)造函數(shù)創(chuàng)建Handler時(shí),它內(nèi)部調(diào)用了另一個(gè)重載的構(gòu)造方法this(null, false)。

public Handler(Callback callback, boolean async) {
    ...//something we just ignore

    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;
}

從構(gòu)造方法中,我們可以看出,handler獲取了與當(dāng)前線程相關(guān)聯(lián)的Looper及MessageQueue的引用。

Handler 發(fā)送消息

創(chuàng)建完Handler之后,我們先從handler.sendMessage()說起:

public class MainActivity extends Activity{
    protected void onCreate(Bundle onSavedInstanceState){
        super.onCreate(onSavedInstanceState);
        setContentView(R.layout.main);
    
        MyRunnable mRunnable = new MyRunnable();
        Thread mThread = new Thread(mRunnable);
        mThread.start();
    }
  
    public static Handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            //do some magic
        }
    };
  
    static class MyRunnable implements Runnable{
        @Override
        public void run(){
            Message msg = Message.obtain();
            //do some magic
            handler.sendMessage(msg);
        }
    }
}

而不管我們調(diào)用sendEmptyMessage()或者是sendMessage(),最終都會(huì)走到這里:

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);
}

關(guān)鍵是最后return時(shí),調(diào)用了enqueueMessage(),我們一起看一下該方法的具體實(shí)現(xiàn):

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

enqueueMessage的方法實(shí)現(xiàn)可以看出,要發(fā)送的消息獲取到了當(dāng)前Handler的引用,也就是msg.target 。然后這條信息被加入到了與當(dāng)前線程相關(guān)聯(lián)的MessageQueue中。到此,發(fā)送消息的邏輯已經(jīng)結(jié)束。
那么Handler處理消息的方法又是在什么時(shí)候回調(diào)的呢?要弄明白這一點(diǎn),我們要對(duì)Looper.loop()進(jìn)行分析。

Looper.loop();

前面我們也已經(jīng)提過,要?jiǎng)?chuàng)建一個(gè)Handler其實(shí)是需要三個(gè)步驟的:

  1. 調(diào)用Looper.prepare();
  2. 創(chuàng)建Handler
  3. 調(diào)用Looper.loop();
    ?
    前面兩步我們已經(jīng)講解過了,那你肯定會(huì)好奇,loop()中到底做了什么呢?我們一起來看一下。
public static void loop() {
    //獲取與當(dāng)前線程相關(guān)聯(lián)的Looper對(duì)象
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //獲取與Looper對(duì)象相匹配的MessageQueue
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ...//something we just ignore

        msg.target.dispatchMessage(msg);

        ...//something we just ignore

        // Mark the message as in use while it remains in the recycled object pool. Clear out all other details.
        msg.recycleUnchecked();
    }
}

從源碼可以看出,loop()其實(shí)調(diào)用了一個(gè)死循環(huán),不斷的從與Looper配套的MessageQueue中取消息,然后調(diào)用msg.target.dispatchMessage(msg);進(jìn)行消息的分發(fā)。
前面Handler發(fā)送消息的時(shí)候,我們已經(jīng)分析過,每個(gè)要發(fā)送的Message都獲取到了發(fā)送它的Handler的引用,也就是msg.target。因此這里msg.target.dispatchMessage(msg);其實(shí)也就是調(diào)用了handler的dispatchMessage進(jìn)行消息的分發(fā)。

Handler的handleMessage()何時(shí)被回調(diào)?

我們一起來看一下handler的dispatchMessage():

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

很明顯,就是在這里,Handler的handleMessage被回調(diào)了。
綜上,我們可以說,是在Looper.loop()中,當(dāng)循環(huán)不斷的從MessageQueue中獲取消息時(shí),間接調(diào)用了Handler的handleMessage()方法。

最后編輯于
?著作權(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)容