Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android源代碼分析]Android消息機制,Handler,Message,Looper,MessageQueue

[Android源代碼分析]Android消息機制,Handler,Message,Looper,MessageQueue

編輯:關於Android編程

最近准備把Android源碼大致過一遍,不敢私藏,寫出來分享給大家,順便記錄一下自己的學習感悟。裡面一定有一些錯誤的地方,希望廣大看客理解理解。網上也有不少分析文章,這裡我盡量分析的更加細致詳盡。不留死角。

一.核心循環體:Looper.loop();

我們知道,在線程run()中Looper.prepare();Looper.looper()。之後這個線程就是一個HandlerThread了。我們可以通過Handler在另外一個線程中(自己也可以)向這個線程發送消息,在這個線程中處理消息。
簡單來說,Looper.loop(),就是一個循環體,循環著從MessageQueue中取消息,處理消息。現在存在幾個問題。這就是整個消息處理框架的核心所在。框架所有的Api(消息的增刪改查)都是為了這個循環體服務的。當然簡單的for(;;)是遠遠不夠的,框架需要考慮到以下問題:
1. 線程安全問題:消息的增刪改查是多線程環境,所以要保證整個消息隊列的線程安全。
2. 線程阻塞問題:當隊列中沒有到期需要處理的消息時,怎樣避免線程空轉浪費性能。
3. 與native層交互問題:我們知道,Android框架層分java和native層,基本我們平時常用在java層常用的核心框架,在native層都有另外一套與之匹配的“分身”,而且java層的眾多功能實現都要依賴native層。
4. 性能問題:比如說Message對象的生滅在這個框架中非常頻繁,可以使用對象緩沖池來提高性能,減輕gc壓力。

1.Looper.looper()的源碼(Android 6.0)
Looper.java(frameworks/base/core/java/android/os/Looper.java)

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
//1.指向static final ThreadLocal sThreadLocal.get()
//相當於一個Map key是Thread.currentThread()
//ThreadLocal知識:http://www.iteye.com/topic/103804
//只是一個本線程持有的變量表而已,隨線程生滅,
//這裡只是取出當前線程對應的looper對象
final Looper me = myLooper();
//2.如果這個線程沒有對應的looper對象,即沒有Looper.prepare();則拋出異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }

//3.從Looper中取出MessageQueue,一個Looper持有一個MessageQueue
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.
//確保這個線程是本地的,因為Handler Message可用於IPC(猜測)
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
    //4.循環體
for (;;) {
    //5.循環取出下一條消息來處理,會在這裡阻塞住,這裡可以猜到消息隊列時一個鏈表結構,先劇透一下上面說的線程阻塞,防止空轉也是在這個函數裡實現的。下面會具體分析。
    Message msg = queue.next(); // might block
    //沒有message即返回
    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);
        }
        //6.消息分發處理,處理消息,最終調用用戶實現的handlerMessage()的地方。下面分析
        msg.target.dispatchMessage(msg);

if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }
        //7.翻譯過來就是:確保在調度過程中的線程的身份沒有被損壞,下面再細說
// 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);
        }
        //將處理完的Message對象回收,以備下次obtain重復使用。
        msg.recycleUnchecked();
    }
}

Looper.prepare()最終調用

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
    }
//為當前線程創建Looper對象,塞進ThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}

此外列出Looper類的成員變量

   private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    //每個線程對應一個Looper,對應多個handler。當在某個線程中調用Looper.Mylooper()時,
    //調用sThreadLocal.get()返回對應該線程的Looper。
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    //全局唯一的主線程對應的MainLooper
    private static Looper sMainLooper;  // guarded by Looper.class
    //每個Looper管理一個MessageQueue
    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;

Looper.java基本結束。

下面通過Message的增刪查處理的順序分析整個框架。

1).下面先說Message的增
api:增的api對應有Handler.sendMessageXXXX,postXXXX,等。
Handler.java(frameworks/base/core/java/android/os/Handler.java)

a.首先得說Handler的初始化:
Handler3個構造函數最終調用兩個版本。

public Handler(Callback callback, boolean async) {
        //如果為真,則檢查內存洩漏,就是判斷自身是否為static類型
if (FIND_POTENTIAL_LEAKS) {
final Class 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;
}

注意這個參數
/*
* Set this flag to true to detect anonymous, local or member classes
* that extend this Handler class and that are not static. These kind
* of classes can potentially create leaks.
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;

這個參數用來檢查可能的內存洩漏,設置這個為true的話,在構造方法中會檢查,自身是否是靜態的內部類,klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC,如果不是就拋出異常。關於內存洩漏,參看我另一篇文章鏈接。

剩下的就是簡單的賦值了。

public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
return queue.enqueueMessage(msg, uptimeMillis);
}

還要注意的是async參數,如果你傳入true,在最後向MessageQueue塞Message的時候會把這個Message設置為異步消息。
什麼是異步消息?先劇透一下,後面要說到一個“同步屏障”的概念,Message鏈表一旦被插入一個“同步屏障”,那麼屏障之後的所有同步消息將不會被處理,哪怕已經到期了。而異步消息則不受影響。
插入動作最後會通過setAsynchronous調用到MessageQueue方法的enqueueSyncBarreir(long when)方法,我們在下面分析。


b.現在拿到Handler對象了,看一下Handler這幾個核心成員變量,可以看到Handler持有一個MessageQueue的引用,一個Looper的引用,這裡的callback,有點像Thread和Runnable的關系,常見的設計模式,指向了用戶handlerMessage的具體實現。

final MessageQueue mQueue;
final Looper mLooper;
//對應handlerMessage的具體實現
final Callback mCallback;
final boolean mAsynchronous;
//IPC相關
IMessenger mMessenger;

說一說IMessenger,IPC相關,相信大家也看的出來,Handler也關聯了Binder提供的IPC服務,Messenger關聯一個可以發送消息的Handler。通過指定一Handler對象創建一個Messenger可以實現基於消息的誇進程通信。
線程和進程主要的差別無非是進程有獨立的內存空間,一旦一個進程將Message通過Binder發送給另外一個進程中的線程的MessageQueue中,那麼,這個Message一樣可以和普通的Message統一處理了。可以說沒毛病。
這方面在後面會具體討論,現在先簡單說一下。


c.handler有了,我們需要獲得一個Message對象,上面說過了,對於Message這種大量朝生夕滅的對象,需要使用對象緩沖池,或者原型模式這些來優化性能,gc最煩的就是這種大量的“生的快,死的早”的對象。我們來看一下Message具體是怎麼做的。
先看一下Message的成員變量,基本上都是熟悉的面孔

Message.java(frameworks/base/core/java/android/os/Message.java)

public int what;
public int arg1; 
public int arg2;
public Object obj;
public Messenger replyTo;

public int sendingUid = -1;

 */
/*package*/ static final int FLAG_IN_USE = 1 <<0;

/*package*/ static final int FLAG_ASYNCHRONOUS = 1 <<1;

/** Flags to clear in the copyFrom method */
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

/*package*/ int flags;

/*package*/ long when;

/*package*/ Bundle data;

/*package*/ Handler target;

/*package*/ Runnable callback;

// sometimes we store linked lists of these things
/*package*/ Message next;

private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

private static boolean gCheckRecycle = true;

rePlyto是Messenger對象,和上面提到的IPC相關,是IPC的信使。
When這個比較重要,他代表了這個Message在什麼時間需要被處理。
sPool就是Message對象緩沖池的鏈表頭。
sPoolSync是同步塊的標志,空對象。
MAX_POOL_SIZE,緩沖池對象最大數量
gCheckRecycle,好像沒什麼用,api大於等於21的時候,非法recycle Message對象的時候會多拋一個異常。


Message對象的獲取,同步方法,需要保證Message鏈表的線程安全。

public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
            Message m = sPool;
sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
        }
    }
    //緩沖池用完即new新對象
return new Message();
}

回收方法,較簡單就不細說了,這裡注意isInUse標志,在Message.next() 中會被置為true,表示Message正在使用,不能回收。

public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
        }
return;
    }
    recycleUnchecked();
}

/**
 * Recycles a Message that may be in-use.
 * Used internally by the MessageQueue and Looper when disposing of queued Messages.
 */
//回收Message並清除裡面的舊數據以備用。
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;

synchronized (sPoolSync) {
if (sPoolSize 

d.現在Message對象拿到手了,下面分析Handler.sendMessage(msg) Handler.java 無論是post(),sendXXX還是等等。都會封裝到Message,計算時間後最終調用到sendMessageAtTime

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

最終調用MessageQueue的enqueueMessage方法 when在前面已經計算出來了,非常好算,加一下就好了 MessageQueue.java(frameworks/base/core/java/android/os/Message.java)

boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
    }
//確保msg不是正在使用的
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
    }
//同步方法,因為MessageQueue和Handler是1對N的關系,也就是說,會有多個線程可能同時調用該方法,所以需要同步處理一下。
synchronized (this) {
    //mQuitting是隊列退出的標志,調用quit方法退出隊列將此標志置為true,接著looper就會退出,HandlerThread結束。
if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
return false;
        }
        //標記msg對象開始使用
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
boolean needWake;
//當when=0/null或者when早於最前面一個msg的when的時候,將此msg插到隊列最前面。這裡的消息隊列是按照when順序排列的。如果這時隊列是阻塞的話,即喚醒隊列。
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
            needWake = mBlocked;
        } else {
// Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
    //只有現在隊列阻塞中並且,message對應的handler為空,並且Message為前面說的異步消息的時候,需要喚醒隊列
needWake = mBlocked && p.target == null && msg.isAsynchronous();
    //遍歷隊列根據when大小找到合適的地點插入。
            Message prev;
for (;;) {
                prev = p;
                p = p.next;
if (p == null || when < p.when) {
break;
                }
if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
prev.next = msg;
        }
        //根據結果判斷是否喚醒隊列(線程),nativeWake是一個native方法,具體後面分析,mPtr是指向native層對應的MessageQueue對象的指針。
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
        }
    }
return true;
}

2.下面說說Message的查,即MessageQueue.next()方法,隊列在這裡阻塞,非常重要。 MessageQueue.java(frameworks/base/core/java/android/os/Message.java)

Message next() {
// Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
//娶到native層的MessageQueue對象指針
final long ptr = mPtr;
if (ptr == 0) {
return null;
    }

int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
    //去除所有在當前線程在內核中掛起的Binder命令,這個調用可能是有用的在做一個可能會阻塞線程很長一段時間的操作情況下,這是為了確保任何掛起的對象引用已被釋放,以防止進程為保持對象的時間比它需要得長。
       //簡單的來說,下面當前線程就要調用nativePollOnce進入長時間的阻塞狀態了,必須通知內核釋放掉該進程在Binder驅動中掛起的對象,不然Binder將長時間無法獲得來自該線程的通知對這些對象進行操作,造成Binder驅動的擁塞。
            Binder.flushPendingCommands();
        }

        //阻塞函數,MessageQueue阻塞於此,實現延時阻塞的真正函數,這是個native函數,下面具體分析
        nativePollOnce(ptr, nextPollTimeoutMillis);
        //同步塊,和上面enqueueMessage裡的那個對應,保證Message鏈表結構的線程安全。
synchronized (this) {
// Try to retrieve the next message.  Return if found.
final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier.  Find the next asynchronous message in the queue.
//遍歷Message鏈表找到一個非空並且不是異步的Message
do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
if (msg != null) {
//如果現在的時間早於Message需要被處理的時間
if (now < msg.when) {
// Next message is not ready.  Set a timeout to wake up when it is ready.
//確定需要延時的時長,即msg的when-現在的時間,和Integer最大值的最大值
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
//不需要延時則可以直接獲得Message,處理一下鏈表,標記Message的使用狀態,返回Message給loop()去處理。
// Got a message.
mBlocked = false;
if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
mMessages = msg.next;
                    }
                    msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
return msg;
                }
            } else {
// No more messages.
nextPollTimeoutMillis = -1;
            }

// Process the quit message now that all pending messages have been handled.
//檢查用戶是否將MessageQueue退出了。
if (mQuitting) {
//這裡的銷毀函數nativeDestroy(mPtr),mPtr = 0;銷毀native層的MessageQueue,並且將其在java層的指針清空。
                dispose();
return null;
            }

// If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.

//方法走到這裡了,代表MessageQueue內暫時沒有需要處理的Message對象,那麼,這時如果用戶設置了idlehandler的話,線程就會“忙裡偷閒”抽空處理一下這個idleHandler。
if (pendingIdleHandlerCount <0
&& (mMessages == null || now <mmessages.when)) 0="" a="" again="" again.="" an="" and="" back="" been="" block="" boolean="" calling="" catch="" code="" could="" count="" delivered="" do="" during="" ever="" final="" first="" for="" go="" handler="" handlers="" handlers.="" have="" i="0;" idle="" idlehandler="" idler="mPendingIdleHandlers[i];" if="" int="" iteration.="" keep="false;" look="" loop="" mblocked="true;" message="" more.="" mpendingidlehandlers="new" new="" nextpolltimeoutmillis="0;" no="" not="" pending="" pendingidlehandlercount="" pre="" reach="" reference="" release="" reset="" run="" run.="" so="" some="" synchronized="" the="" them="" this="" threw="" throwable="" to="" try="" wait="" waiting.="" we="" while="" without="" data-cke-pa-only="">

3.然後是消息的刪除,這個倒是沒什麼好說的,比較簡單

void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
    }

synchronized (this) {
        Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h&& p.what == what
&& (object == null || p.obj == object)) {
            Message n = p.next;
mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

// Remove all messages after front.
while (p != null) {
            Message n = p.next;
if (n != null) {
if (n.target == h&& n.what == what
&& (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
continue;
                }
            }
            p = n;
        }
    }
}

最後,這一篇基本完成了,可能我的理解會有些錯誤,歡迎指正,下面一篇就是分析native層中的這幾個函數。

private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved