Handler機(jī)制分析

最近翻譯了一片關(guān)于Context泄露的文章,其中提到了Handler的一些知識(shí)點(diǎn)。想想當(dāng)初自己研究這塊的時(shí)候也是看著源碼一點(diǎn)點(diǎn)摳出來的。只不過那時(shí)候沒有做個(gè)總結(jié),現(xiàn)在正好借著這個(gè)機(jī)會(huì)把這塊知識(shí)點(diǎn)總結(jié)下,也算是做個(gè)備注了。

我們知道Android應(yīng)用啟動(dòng)的時(shí)候會(huì)執(zhí)行ActivityThread類的main方法,詳情請(qǐng)參見羅升陽的這篇文章。main方法中會(huì)為主線程創(chuàng)建一個(gè)Looper對(duì)象,這個(gè)Looper中維護(hù)了一個(gè)消息隊(duì)列MessageQueen。Looper會(huì)不斷的從消息隊(duì)列中取消息,然后交給消息的target對(duì)象(即Handler)去處理這個(gè)消息。如果隊(duì)列中沒有消息,那么Looper就會(huì)進(jìn)入等待狀態(tài)直到隊(duì)列中有新消息。大概的過程就是這樣,下面我們通過源碼來了解下整個(gè)過程。

首先來看看ActivityThread的main方法,這里只保留了跟本文相關(guān)的主要代碼。

public static void main(String[] args) {

    Looper.prepareMainLooper();

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

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    Looper.loop();
}

main方法中首先調(diào)用了Looper.prepareMainLooper()來為主線程創(chuàng)建一個(gè)Looper對(duì)象,然后在調(diào)用Looper.loop()方法進(jìn)入一個(gè)無限循環(huán)狀態(tài)不斷的從消息隊(duì)列中取消息進(jìn)行處理。那么,我們?cè)俑櫟?code>Looper.prepareMainLooper()中去看看。

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

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

prepareMainLooper()首先調(diào)用Looper的prepare()方法創(chuàng)建Looper對(duì)象,然后再把這個(gè)looper對(duì)象賦值給sMainLooper。同時(shí)在創(chuàng)建過程中確保了主線程只有一個(gè)Looper對(duì)象。Looper對(duì)象在創(chuàng)建的時(shí)候會(huì)同時(shí)創(chuàng)建一個(gè)MessageQueen對(duì)象,所有的消息都會(huì)存儲(chǔ)在這個(gè)隊(duì)列中。Looper也是從這個(gè)隊(duì)列中取消息來進(jìn)行處理的。并且,這個(gè)Looper對(duì)象的作用域?yàn)檎麄€(gè)線程。 這樣,只要是在該線程內(nèi)發(fā)送的消息,都會(huì)發(fā)送到這個(gè)Looper對(duì)象的消息隊(duì)列中進(jìn)行處理。

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

main方法最后調(diào)用了Looper的loop()方法讓Looper工作起來,也就是處理消息隊(duì)列中的消息。

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

        msg.target.dispatchMessage(msg);
    }
}

loop()方法先拿到當(dāng)前線程的Looper對(duì)象,然后再拿到Looper的MessageQueen對(duì)象。最后進(jìn)入無限循環(huán),不斷的從消息隊(duì)列中取出消息。然后再把消息交給這個(gè)消息的target對(duì)象進(jìn)行處理。那么現(xiàn)在的問題就是消息是從哪里來的以及這個(gè)target對(duì)象又是誰。

一般情況下,我們會(huì)通過handler的sendMessage(msg)方法來發(fā)送一條消息。那么我們就跟蹤下這個(gè)方法,看看這個(gè)消息最終被發(fā)送到哪里去了。

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;
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//注意:這里把this(即發(fā)送消息的那個(gè)Handler對(duì)象)賦值給了消息的target對(duì)象。
                    //所以,在Looper.loop()方法中的target就是一個(gè)Handler對(duì)象
    return queue.enqueueMessage(msg, uptimeMillis);
}

可以看到通過層層調(diào)用,最終調(diào)用了sendMessageAtTime()方法,該方法又調(diào)用了enqueueMessage()方法將方法放入一個(gè)消息隊(duì)列中。那么這個(gè)消息隊(duì)列又跟Looper中的消息隊(duì)列有啥關(guān)系呢?我們來看看Handler是怎么創(chuàng)建的。

public Handler() {
    this(null, false);
}

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

已經(jīng)很清晰明了了。當(dāng)創(chuàng)建Handler對(duì)象的時(shí)候,首先會(huì)通過Looper.myLooper()拿到當(dāng)前線程的Looper對(duì)象,然后再拿到Looper的MessageQueen對(duì)象。也就是說我們的消息是被發(fā)送到當(dāng)前線程的Looper的消息隊(duì)列中了。這樣Looper.loop()拿到的消息就是我們發(fā)送的消息,然后再把消息交給發(fā)送這個(gè)消息的Hanlder來進(jìn)行處理。即Looper.loop()中的msg.target.dispatchMessage(msg)。那么我們?cè)賮砜纯?code>handler.dispatchMessage(msg)是怎么處理這個(gè)消息的。

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

我們這里暫時(shí)不關(guān)心msg的callback以及handler的mCallback。這里最終會(huì)調(diào)用handleMessage(msg)方法,那我們當(dāng)然要追蹤進(jìn)去看看了。

public void handleMessage(Message msg) {
}

沒錯(cuò),是個(gè)空方法。其實(shí)這里就是我們使用Handler的時(shí)候?qū)崿F(xiàn)我們處理消息邏輯的地方。一般我們是這么使用Handler的:

private static Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //處理邏輯
    }
};

至此,整個(gè)Handler機(jī)制就串通了:從消息的發(fā)送到消息的處理。

如果我們?cè)谥骶€程中使用Handler,那我們不用去管Looper。因?yàn)?,framew已經(jīng)為我們的主線程創(chuàng)建好了Looper。但是,如果我們要在其他線程中使用Handler這套機(jī)制,那我們就需要自己去創(chuàng)建Looper并調(diào)用Looper.prepare(),否則就會(huì)發(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)容