源碼分析Looper、Handler、Message之間的關係

/**   

            Handler、Looper、Message三者之間的關係,無外乎就是開始Looper會開始無限的循環,目的是在消息隊列中進行獲取Message,有則取無在等;而Handler則是在發送Message和handlerMessage方面起作用,發送的Message則是發送到消息隊列中,handlerMessage則是處理Looper發過來的消息

*/

先附一張三者關係圖方便理解


源碼分析

首先我們來看一下Handler的構造方法

    /**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn't one, this handler won't be able to receive messages.
     */
    public Handler() {
        ...
        //獲取Looper對象 
       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 = null;
    }
      這裏有一個判斷,這裏的判斷主要的針對子線程new Handler的情況,因爲在主線程Looper會自動創建在子線程裏則沒有。

爲了驗證我們來看主線程的方法ActivityThread類main方法

    public static final void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

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

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();
        ...
    }
}
Looper.prepareMainLooper()

    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    
    public static final void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }
         從代碼中可以看出其實main方法就是調用了prepare方法,而這個方法是將new Looper()放入ThreadLocal裏面,所謂ThreadLocal類也HashMap是一樣的,只不過它裏面默認是將Key存儲的每個線程,用途:保證每個線程所擁有的value是唯一的。ok,我們接下來看Handler的構造方法

Looper.myLooper()方法

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }
這裏只是將ThreadLocal類裏面存入的Looper取出來,然後我們看ActivityThread類裏面

Loop.loop()方法

   /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;
        ...
        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                msg.target.dispatchMessage(msg);
                ...
            }
        }
    }
      調用這個方法就進入了無限循環中,Looper將從MessageQueue中不斷的取消息(有的時候則取沒有的時候等待),當取到數據的時候會調用msg.target.dispatchMessage(msg)方法將Message回傳到Handler中。target是什麼呢?其實你順着源碼查看你會發現target其實是Handler對象,更準確的是該Message所屬Handler對象。

msg.target.dispatchMessage(msg)方法

    /**
     * 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);
        }
    }
         這裏的msg.callback和mCallback在Message和Handler創建的時候有相應的參數,這裏最後的情況纔是去執行handler的handlerMessage方法,這裏需要注意嘍,如果你在Message和Handler裏面使用Callback就不會在調用handlerMessage。

對於Looper取消息和發送消息就是這些,接下來來看一下Handler的發送消息到消息隊列的過程

最終調用的sendMessageAtTime()方法

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
      每次的發送中將當前發送的Handler對象賦值給target ,整好對應上面Looper取出Message之後根據target分發給相應的Handler的過程。

MessageQueue.enqueueMessage()方法

    final boolean enqueueMessage(Message msg, long when) {
        ...
            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }

在第一個if語句中通過比較傳入的when和隊列中第一個Message的when的大小,如果傳入的小則需要馬上進行處理,將needWake喚醒的狀態置爲true

否則的話將對消息隊列進行遍歷將傳入的Message根據when插入到裏面,並且將喚醒狀態置爲false。


到這裏三者關係就大致講完了,如果想了解更多請看鴻洋大神的: Android 異步消息處理機制 讓你深入理解 Looper、Handler、Message三者關係

發佈了59 篇原創文章 · 獲贊 10 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章