承接上一篇Handler系列一,上篇主要總結了Handler如何通訊,這篇來介紹Handler怎麼通訊。git
Handler及其關聯的類圖github
以上類圖能夠快速幫助咱們理清Handler與Looper、MessageQueue的關係,如下從源碼的角度慢慢分析:segmentfault
上一段很熟悉的代碼:數組
Message msg =Message.obtain(); //從全局池中返回一個message實例,避免屢次建立message(如new Message) msg.obj = data; msg.what=1; //標誌消息的標誌 handler.sendMessage(msg);
從sendMessageQueue開始追蹤,函數調用關係:sendMessage -> sendMessageDelayed ->sendMessageAtTime,在sendMessageAtTime中,攜帶者傳來的message與Handler的mQueue一塊兒經過enqueueMessage進入隊列了。less
對於postRunnable而言,經過post投遞該runnable,調用getPostMessage,經過該runnable構造一個message,再經過 sendMessageDelayed投遞,接下來和sendMessage的流程同樣了。async
在enqueueMessage中,經過MessageQueue入隊列,併爲該message的target賦值爲當前的handler對象,記住msg.target
很重要,以後Looper取出該消息時,還須要由msg.target.dispatchMessage
回調到該handler中處理消息。ide
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在MessageQueue中,由Message的消息鏈表進行入隊列函數
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { 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.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; 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. needWake = mBlocked && p.target == null && msg.isAsynchronous(); 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; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
構造Looper時,構建消息循環隊列,並獲取當前線程oop
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
但該函數是私有的,外界不能直接構造一個Looper,而是經過Looper.prepare來構造的:post
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));
}
這裏建立Looper,並把Looper對象保存在sThreadLocal中,那sThreadLocal是什麼呢?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
它是一個保存Looper的TheadLocal實例,而ThreadLocal是線程私有的數據存儲類,能夠來保存線程的Looper對象,這樣Handler就能夠經過ThreadLocal來保存於獲取Looper對象了。
TheadLocal 如何保存與獲取Looper?
public void set(T value) {
Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value);
}
public T get() {
// Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this);
}
在 set 中都是經過 values.put
保存當前線程的 Looper 實例,經過 values.getAfterMiss(this)
獲取,其中put
和getAfterMiss
都有key
和value
,都是由Value對象的table數組保存的,那麼在table數組裏怎麼存的呢?
table[index] = key.reference; table[index + 1] = value;
很顯然在數組中,前一個保存着ThreadLocal對象引用的索引,後一個存儲傳入的Looper實例。
在loop
中,一個循環,經過next
取出MessageQueue中的消息
若取出的消息爲null,則結束循環,返回。
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(); } }
Looper把消息回調到handler的dispatchMessage中進行消息處理:
runnable
時,把runnable
對象賦值給了message的callback
。callback
建立handler方式去處理。public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
以一個時序圖來總結handler的消息機制,包含上述如何關聯Looper和MessageQueue的過程。
Handler-Looper-MessageQueue時序圖
本文發表於我的博客:http://lavnfan.github.io/,歡迎指教。