閱讀Hanlder、Looper、Message的源碼

經典例子

首先是創建一個 Handler

private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                mTextView.setText("更新了UI");
                break;
        }
    }
};

在子線程中更新UI

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);  // 在子線程做一段耗時操作,比如進行網絡請求
            mHandler.sendEmptyMessage(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

找到看源碼的切入點

從這個經典的例子中來讀源碼,源碼的切入點就可以從 Handler 的無參構造方法開始看起。

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

這個無參構造方法調用了另外一個構造方法 this(null, false);。去除方法體里面其他的無關代碼,得到關鍵代碼如下

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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;
    
    // ...
}

看一下這個兩句話是什么意思

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

看一下 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 @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

只是返回一個 Looper 對象而已,也就是獲取了當前線程保存的 Looper 實例,看一下 sThreadLocal 這個變量是什么東西,用 CTRL-F 查找一下代碼,整個 Looper 類中只有這幾個地方有用到 sThreadLocal 變量

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

/** Initialize the current thread as a looper.
  * This gives you a chance to create handlers that then reference
  * this looper, before actually starting the loop. Be sure to call
  * {@link #loop()} after calling this method, and end it by calling
  * {@link #quit()}.
  */
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));
}

主要看 prepare(boolean quitAllowed) 這個方法就可以了。sThreadLocal 是一個 ThreadLocal 對象,可以在一個線程中存儲變量。

1 public static final void prepare() {  
2    if (sThreadLocal.get() != null) {  
3        throw new RuntimeException("Only one Looper may be created per thread");  
4    }  
5    sThreadLocal.set(new Looper(true));  
6 }

第 5 行新建一個 Looper 對象放入 sThreadLocal 對象。2~4 行判斷 sThreadLocal 中是否已經有 Looper 對象了,如果有就會拋出異常,說明一個線程只能有一個 Looper 對象。

看一下 new Looper(true) 這句話做了什么事情

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

創建了一個消息隊列 MessageQueue,還有獲取了當前線程的實例。

到這里就不知道要看什么了,那就看一下類的注釋好了,說不定有線索

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */
public final class Looper {
    // ...
}

注釋說 Looper 類是用來為一個線程創建一個消息循環用的。線程默認是沒有消息循環的,可以調用 prepare() 創建消息循環,調用 loop() 去處理消息。通常情況下是用 Handler 類和消息循環交互。

這段注釋提到了 prepare()loop() 方法。prepare() 方法剛才已經看過了,那就看一下 loop() 方法做了什么。去掉一些無關的語句,得到

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

    // ...

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

        // ...

        try {
            msg.target.dispatchMessage(msg);
        } finally {
            // ...
        }

        // ...

        msg.recycleUnchecked();
    }
}

這段代碼的大概意思是

無限循環去遍歷消息隊列,取出隊列中的 Message 對象,然后調用 msg.target.dispatchMessage(msg); ,然后再把 Message 回收了

msg.target.dispatchMessage(msg); 這句話不明白,進入 Message 類看一下是什么東西。

Handler target;

從這里可以知道 HandlerMessage 有一腿。

再看一下 Handler 類中 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);
    }
}

這里應該就是調用各種回調方法了。從剛才寫的經典例子中,我沒有寫任何的回調方法,因此這個方法體最后就進入了 handleMessage(msg); 方法中。看一下這個方法做了什么

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

這個方法就是經典例子中重寫的 handlerMessage 方法

private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                mTextView.setText("更新了UI");
                break;
        }
    }
};

現在梳理一下

  • Looper 在 prepare() 方法中創建一個 Looper 實例和一個消息隊列
  • Looper 在 loop() 方法中不斷地遍歷消息隊列,調用 MessageQueue.next() 取出 Message,然后調用和 Message 綁定的 HandlerdispatchMessage 方法,去調用各種回調方法

現在幾個疑問

  • Message 是怎么創建的?
  • Message 是怎么進入 Looper 的消息隊列的?
  • Handler 是怎么和 Message 綁定在一起的?

Message 是怎么創建的?

在使用 Handler 異步更新 UI 的時候,都會創建 Message 攜帶我們想要傳遞的數據。Message 有幾個屬性可以攜帶數據:

what、arg1、arg2obj 。用法如下

Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = 2;
msg.arg2 = 3;
msg.obj = myObj // myObj 是我們想通過 Message 攜帶的對象
mHandler.sendMessage(msg);

看一下 mHandler.obtainMessage() 做了什么

/**
 * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
 * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
 *  If you don't want that facility, just call Message.obtain() instead.
 */
public final Message obtainMessage()
{
    return Message.obtain(this);
}

又調用了 Message.obtain(this),再進入看看

/**
 * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
 * @param h  Handler to assign to the returned Message object's <em>target</em> member.
 * @return A Message object from the global pool.
 */
public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

可以看到,為了提高性能,先調用 Message m = obtain(); 從消息池中取出一個 Message,然后再將 Handler 實例賦值給 Messagetarget 屬性,這樣就將 HandlerMessage 綁定在一起了。

Message是怎么和Handler綁定在一起的?

從上面的

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

我們已經知道了

Message 是怎么進入 Looper 的消息隊列的?

看一下剛才寫的代碼

Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = 2;
msg.arg2 = 3;
msg.obj = "想要攜帶的對象";
mHandler.sendMessage(msg);

Message 已經通過 Handler.obtainMessage() 獲取到了,然后就是調用 Handler.sendMessage(Message msg) 發出消息??匆幌?mHandler.sendMessage(msg); 做了什么

/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

又調用了另外一個方法,再點進去看看

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

怎么又調用了另外一個方法,再點進去看看

/**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
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);
}

從這個方法體可以看出,是把剛才我們創建的 Message 加入隊列中去。這里有句話

MessageQueue queue = mQueue;

這個消息隊列是哪里來的?Handler 類中怎么會有消息隊列?用 CTRL-F 查找一下 mQueue = 在哪里出現過

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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 的這個構造方法中找到了 mQueue 被賦值的地方

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

它是通過調用 Looper 的靜態方法 myLooper() 獲取到 Looper 對象,然后再通過 Looper 對象進而獲取到 Looper 的消息隊列的。

知道了 Handler 中的 mQueue 是怎么獲取到的,那就再接著往下看

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

這個方法又調用了 enqueueMessage(queue, msg, uptimeMillis),點進去看一下做了什么

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

在這里,這個方法調用了消息隊列 MessageQueueenqueueMessage() 方法把 Message 放進去。

enqueueMessage() 這個方法的方法體代碼太多,我看不懂。不過只需要知道一件事,這個方法的指責是將 Message 放入 MessageQueue 就好了。

梳理Looper、Handler、Message、MessageQueue關系

  • Looper 在 prepare() 方法中創建一個 Looper 實例和一個消息隊列
  • Looper 在 loop() 方法中不斷地遍歷消息隊列,調用 MessageQueue.next() 從消息隊列中取出 Message,然后調用和 Message 綁定的 HandlerdispatchMessage 方法,去調用各種回調方法
  • Handler 的構造方法會獲得當前線程中的 Looper 實例,進而和 MessageQueue 關聯在一起
  • Handler 調用 sendMessage(Message msg),會將 msg.target 賦值為自己,然后放入 MessageQueue
  • 我們在構造 Handler 實例的時候,會重寫 handleMessage 方法,也就是 msg.target.dispatchMessage(msg) 最終調用的方法

Looper.prepare()又是誰來調用的?

從剛才的源碼中,可以知道是通過調用 Looper.prepare() 來創建 Looper 對象。同時,從經典例子中發現,我們沒有去調用 Looper.prepare() 方法。那么 Looper.prepare() 又是誰來調用的?

查了下資料,Android 應用程序的入口是 ActivityThreadmain 函數,那就去看一下 main 函數是怎么實現的,可以看到,在方法體中有一句 Looper.prepareMainLooper();

public final class ActivityThread {

    public static void main(String[] args) {
        // ...

        Looper.prepareMainLooper();

        // ...
        
        Looper.loop();      
    }
}

看一下這個方法的方法體

/**
 * Initialize the current thread as a looper, marking it as an
 * application's main looper. The main looper for your application
 * is created by the Android environment, so you should never need
 * to call this function yourself.  See also: {@link #prepare()}
 */
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

它調用了 prepare() 創建了 Looper 實例。

以上就是 UI 線程 Looper 創建過程

參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容