深入理解Android非同步訊息處理機制

yifanwu發表於2021-09-09

一、概述

Android 中的非同步訊息處理主要分為四個部分組成,Message、Hndler、MessageQueue 和 Looper。其關係如下圖所示:

圖片描述

1. Message 是執行緒之間傳遞的訊息,它可以在內部攜帶少量資訊,用於在不同執行緒之間交換資料。

2. MessageQueue 是訊息佇列,它主要用於存放所有由 Handler 傳送過來的訊息,這部分訊息會一直在訊息佇列中,等待被處理。每個執行緒中只會有一個 MessageQueue 物件。

3. Handler 是處理者,它主要用於傳送和處理訊息。 傳送訊息一般使用 handler  的 sendMessage()方法,處理訊息會呼叫 handleMessage() 方法。

4. Looper 是每個執行緒中 MessageQueue 的管家, 呼叫 loop() 方法後,就會進入到一個無限迴圈當中,然後每當發現 MessageQueue 中存在一條訊息,就會將其取出,並傳遞到 handleMessage()方法當中。每個執行緒中也只會有一個Looper物件。

二、詳細介紹

是一個ThreadLocal物件,可以在一個執行緒中儲存變數。Looper 就是儲存在sThreadLocal裡面。這個方法被呼叫後,首先會判斷當前執行緒裡面有沒有 Looper物件,如果沒有就會建立一個  Looper 物件,如果存在則會丟擲異常。可見,prepare()方法,不能被呼叫兩次。這就保證了一個執行緒只有一個Looper物件。

接下來我們看一下Looper的建構函式:

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

在 Looper 的建構函式中,建立了 MessageQueue 物件,這也保證了一個執行緒只有一個 MessageQueue 物件。

然後我們看看 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("

這個方法先呼叫 myLooper() 方法,得到 sThreadLocal 中儲存的 Looper 物件,並得到 looper 物件對應的 MessageQueue 物件,然後就進入無限迴圈。

該迴圈主要包括:取出一條訊息,如果沒有訊息則阻塞; 呼叫  msg.target.dispatchMessage(msg);把訊息交給msg的target的dispatchMessage方法去處理。

Looper主要作用:

1、 與當前執行緒繫結,保證一個執行緒只會有一個Looper例項,同時一個Looper例項也只有一個MessageQueue。
2、 loop()方法,不斷從MessageQueue中去取訊息,交給訊息的target屬性的dispatchMessage去處理。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2157/viewspace-2806315/,如需轉載,請註明出處,否則將追究法律責任。

相關文章