Android中的Handler、Looper、Message、MessageQueue之間流程關(guān)系

Handler、Looper、Message、MessageQueue這四者的關(guān)系,用比較通俗的方式解釋,可以理解為:Looper是傳送帶在不停的運(yùn)送貨物,MessageQueue是傳送帶上面的貨物隊(duì)列,Message就是貨物隊(duì)列中一個(gè)一個(gè)的貨物,而Handler則是貨物被消費(fèi)的地方。
Looper的分析

Looper是整個(gè)消息機(jī)制的關(guān)鍵節(jié)點(diǎn),Looper類用來(lái)為一個(gè)線程開啟一個(gè)消息循環(huán)。主線程是默認(rèn)開啟的,但是新的線程是默認(rèn)不開啟的,所以我們使用Handler從主線程或其他線程往子線程發(fā)消息,是會(huì)拋出沒(méi)有Looper對(duì)象這個(gè)錯(cuò)誤,這里我們?nèi)绻胪泳€程發(fā)送消息,那么必須在子線程中調(diào)用Looper.prepar()啟動(dòng)Looper,然后再調(diào)用Looper.loop()讓Looper開始工作。每個(gè)Looper都有與之對(duì)應(yīng)的MessageQueue當(dāng)執(zhí)行Looper.loop后MessageQueue的消息就開始被處理了。這里需要注意的是,Looper.loop是一個(gè)循環(huán),當(dāng)有消息時(shí)處理消息,沒(méi)有消息時(shí)掛起。所以Looper.loop之后的代碼是無(wú)法運(yùn)行的。如過(guò)需要運(yùn)行之后的代碼,需要執(zhí)行當(dāng)前線程的handler.getLooper.quit()使Looper退出消息處理,循環(huán)結(jié)束后面代碼就可以運(yùn)行了。


Looper和Handler、Message、MessageQueue的關(guān)系

要想了解Looper和Handler、Message、MessageQueue的關(guān)系我們最好能從源碼的角度將發(fā)送消息到消息隊(duì)列再到分發(fā)處理消息的整個(gè)流程重新走一邊。

  • 首先創(chuàng)建的是Looper我們這里看下Looper的構(gòu)造方法:

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

這里可以看到當(dāng)啟動(dòng)了Looper后會(huì)創(chuàng)建一個(gè)MessageQueue與之綁定,并且綁定當(dāng)前線程。

有了Looper這個(gè)傳送帶和MessageQueue這個(gè)貨物隊(duì)列,我們?cè)倏纯窗l(fā)送與收取貨物的Handler的構(gòu)造方法:
空參的構(gòu)造函數(shù)執(zhí)行了 this(null, false);所以也就是執(zhí)行了Handler(Callback callback, boolean async)這個(gè)構(gòu)造函數(shù)下面我們看這個(gè)構(gòu)造函數(shù)

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        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中的構(gòu)造方法中上面那個(gè)if是打印內(nèi)存泄漏的日志, Looper.myLooper()用來(lái)獲取當(dāng)前線程的Looper對(duì)象,如果沒(méi)有則拋出錯(cuò)誤,就是Looper分析中提到的沒(méi)有Looper對(duì)象的問(wèn)題,解決方法也在那段中說(shuō)明了,下面再通過(guò)mLooper.mQueue獲取當(dāng)前線程的MessageQueue對(duì)象。下面我們有了Looper這個(gè)對(duì)象就可以以他為基礎(chǔ)通過(guò)Handler進(jìn)行通訊了。

Handler發(fā)送消息時(shí)可以設(shè)置不同的參數(shù),設(shè)置延時(shí)發(fā)送等等很多種方法,但是最后都會(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);
    }

從這段代碼我們可以看到,msg被添加到由了構(gòu)造函數(shù)傳入的MessageQueue中,最后執(zhí)行了enqueueMessage(queue, msg, uptimeMillis)方法進(jìn)入MessageQueue隊(duì)列 :

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

注意這段代碼中的這句:msg.target = this;這句代碼表明這個(gè)msg的target的明確就是this也就是本類,所以后面消息分發(fā)時(shí)也會(huì)分發(fā)到這個(gè)target就是本類。

現(xiàn)在消息已經(jīng)傳遞到了Looper中,下面我們看看在Looper中消息是怎么分發(fā)的。
Looper中的消息分發(fā)的關(guān)鍵是loop()方法,下面看看這個(gè)方法的源碼:

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    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;

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

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

從上面代碼中可以明顯看到幾個(gè)關(guān)鍵方法

  1. queue.next():在死循環(huán)中,不斷的通過(guò)queue.next獲取消息,
  2. msg.target.dispatchMessage(msg) :注意這里的target就是上面我們分析的那個(gè)target即發(fā)送消息的那個(gè)Handler對(duì)象,這里將消息隊(duì)列中的消息進(jìn)行了分發(fā)。
  3. msg.recycleUnchecked():這個(gè)方法是當(dāng)消息被分發(fā)掉,對(duì)消息進(jìn)行正在使用的標(biāo)記。

消息已經(jīng)分發(fā)完了,下面又回到了,Hanlder中處理消息了,那么我們常用的handler.handleMessage(msg)方法又是什么時(shí)候調(diào)用的呢,在上面那段的第2個(gè)關(guān)鍵方法msg.target.dispatchMessage(msg) 這個(gè)方法其實(shí)就是調(diào)用了target中的dispatchMessage()方法,這個(gè)target就是handler,所以我么再回到Handler的源碼中,看看這個(gè)dispatchMessage()是怎么接收消息的:

 /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

從這段代碼中,可以明確的看到執(zhí)行了handleMessage(msg)這個(gè)方法,到此整個(gè)消息發(fā)送到接收的流程已經(jīng)全部結(jié)束了。


總結(jié)

通過(guò)以上的分析可以知道 Looper.loop()不斷地獲取MessageQueue中的Message,然后調(diào)用與Message綁定的Handler對(duì)象的dispatchMessage方法,最后handleMessage就在dispatchMessage方法里被調(diào)用了。從這些源碼中可以看到,不同的handler對(duì)象可以設(shè)置不同的target消息也會(huì)分發(fā)到不同的handleMessage方法中,所以可以得出結(jié)論,Looper可以有多個(gè)handler與之綁定并向他發(fā)送消息,但是只能有一個(gè)對(duì)應(yīng)的線程,同時(shí)也只能有一個(gè)MessageQueue。

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