以前寫過一篇文章,概述了Android應用程序消息處理機制。本文在此文基礎上,在源碼級別上展開進行概述html
Handler的使用方法以下所示:android
Handler myHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { ... } } }; class myThread implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { Message message = Message.obtain(); message.what = TestHandler.GUIUPDATEIDENTIFIER; TestHandler.this.myHandler.sendMessage(message); message.recycle(); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
或者:框架
mHandler=new Handler(); mHandler.post(new Runnable(){ void run(){ ... } });
又或者:async
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(); } }
首先看其構造函數:ide
new Handler() ... public Handler() { this(null, false); } ... public Handler(Looper looper, Callback callback) { this(looper, callback, false); } ... public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { // 默認爲false,若爲true則會檢測當前handler是不是靜態類 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()); } } // 1. 得到當前線程的looper mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //2. 得到looper上的message queue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
由此引入了兩個關鍵對象Looper和MessageQueue。函數
先看 mLooper = Looper.myLooper();
這一句發生了什麼:oop
public static Looper myLooper() { return sThreadLocal.get(); }
能夠看到,該方法返回一個sThreadLocal對象中保存的Looper。關於ThreadLocal類,請參考這裏,本文不展開。
若是還沒有在當前線程上運行過Looper.prepare()的話,myLooper會返回null。接下來看看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對象,並將其保存在sThreadLocal中。接下來看一下Looper的構造函數。ui
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
調用完Looper.prepare()後,需調用Looper.loop()才能使消息循環運做起來,其源碼以下所示:this
public static void loop() { final Looper me = myLooper(); //1. 取出looper對象 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; //2. 取出looper綁定的message queue // 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(); // loop time. long tm = 0; ... for (;;) { Message msg = queue.next(); // 3. 堵塞式在message queue中取數據 if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); 4. 分發message到指定的target handler ... // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { ... } msg.recycleUnchecked(); // 5. 回收message對象 ... } }
能夠簡單地將Looper.loop()理解成一個不斷檢測message queue是否有數據,如有即取出並執行回調的死循環。 接下來看一下Message類:
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; ... /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; }
what、arg一、arg2這些屬性本文不做介紹,咱們把目光集中在next、sPoolSync、sPool、sPoolSize這四個靜態屬性上。
當咱們調用Message.obtain()時,返回了一個Message對象。Message對象使用完畢後,調用recycle()方法將其回收。其中obtain方法的代碼以下所示:
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; } } return new Message(); }
能夠看到,obtain方法被調用時,首先檢測sPool對象是否爲空,若不然將其當作新的message對象返回,並「指向"message對象的next屬性,sPoolSize自減。能夠看出message對象經過next屬性串成了一個鏈表,sPool爲「頭指針」。再來看看recycle方法的實現:
public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it is still in use."); } return; } recycleUnchecked(); } 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 < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
若是message對象不是處於正在被使用的狀態,則會被回收。其屬性所有恢復到原始狀態後,放在了鏈表的頭部。sPool對象「指向」它,sPoolSize自增。
綜上能夠看出,經過obtain和recycle方法能夠重用message對象。經過操做next、sPoolSync、sPool、sPoolSize這四個屬性,實現了一個相似棧的對象池。
msg.target爲handler類型,即向handler成員的dispatchMessage方法傳入msg參數,其實現以下所示:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
這裏能夠看到回調了各類接口。
到目前爲止,咱們知道了如何處理在消息隊列裏面的msg對象,但仍不知道msg對象是如何放到消息隊列裏面的。一般來講,咱們經過Handler的sendMessage(msg)方法來發送消息,其源碼以下所示:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } ... public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } ... 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); } ... private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
可知sendMessage最終會調用queue.enqueueMessage(msg, uptimeMillis)將msg對象保存至message queue中,uptimeMillis表示msg執行回調的時刻。 咱們來看一下MessageQueue類的enqueueMessage方法:
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("MessageQueue", e.getMessage(), e); msg.recycle(); return false; } // 1.設置當前msg的狀態 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; // 2.檢測當前頭指針是否爲空(隊列爲空)或者沒有設置when 或者設置的when比頭指針的when要前 if (p == null || when == 0 || when < p.when) { // 3. 插入隊列頭部,而且喚醒線程處理msg msg.next = p; mMessages = msg; needWake = mBlocked; } else { //4. 幾種狀況要喚醒線程處理消息:1)隊列是堵塞的 2)barrier,頭部結點無target 3)當前msg是堵塞的 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; } } // 5. 將當前msg插入第一個比其when值大的結點前。 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; }
結合註釋,咱們能夠了解到msg push到queue中時,queue的狀態的變化和處理隊列的邏輯。
前文中Looper對象的loop方法中:
for (;;) { ... Message msg = queue.next(); // 3. 堵塞式在message queue中取數據 if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); 4. 分發message到指定的target handler ... }
能夠看出,message queue的next方法被調用時,可能會發生堵塞。咱們來看一看message queue的next方法:
Message next() { // 1. 判斷當前loop是否已經使用過,下文會解釋這個mPtr final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; // 2. 進入死循環,直到獲取到合法的msg對象爲止。 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); // 這個是什麼? } // 3. 進入等待,nextPollTimeoutMillis爲等待超時值 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // 4. 獲取下一個msg final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 當前節點爲barrier,因此要找到第一個asynchronous節點 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 當前隊列裏最先的節點比當前時間還要晚,因此要進入堵塞狀態,超時值爲nextPollTimeoutMillis nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // 刪除當前節點,並返回 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); return msg; } } else { // 頭結點指向null nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // 5. 若是當前狀態爲idle(就緒),則進入idle handle的代碼塊 // 進入idle的狀況有:隊列爲空;隊列頭元素blocking; if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // 6. 本輪喚醒(next被調用)時沒處理任何東西,故再次進入等待。 mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // 在一次next調用中,這個代碼塊只會執行一次 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { // 若是返回true,則idler被保留,下次next的idle時會被調用。 keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
代碼執行流程見註釋。其中IdleHandler是一個接口:
public static interface IdleHandler { boolean queueIdle(); }
IdleHandler提供了一個在MessageQueue進入idle時的一個hook point。更多時與barrier機制一塊兒使用,使message queue遇到barrier時產生一個回調。
前面涉及到的幾個主要的類Handler、Looper、MessageQueue和Message的關係以下所述:
Handler負責將Looper綁定到線程,初始化Looper和提供對外API。
Looper負責消息循環和操做MessageQueue對象。
MessageQueue實現了一個堵塞隊列。
Message是一次業務中全部參數的載體。
框架圖以下所示:
+------------------+ | Handler | +----+--------^----+ | | send | | dispatch | | v | +----- <---+ | | | Looper | | | | | +---> -----+ | ^ enqueue| | next | | +--------v------+----------+ | MessageQueue | +--------+------^----------+ | | nativePollOnce | | nativeWake | | +-----------------v------+---------------------+ Lower Layer
最後,留意到MessageQueue中有4個native方法:
// 初始化和銷燬 private native static long nativeInit(); private native static void nativeDestroy(long ptr); // 等待和喚醒 private native static void nativePollOnce(long ptr, int timeoutMillis); private native static void nativeWake(long ptr); // 判斷native層的狀態 private native static boolean nativeIsIdling(long ptr);
將會在後續文章中進行介紹。