標籤:ebe not back event amp void cat corrupt safe
Looper準備
Handler執行個體化時,會從當前線程擷取Looper,從而獲得MessageQueue,用於發送訊息。然後,線程不是生來就有Looper對象的,需要線上程執行中調用靜態方法Looper.prepare(),最終會調用到如下靜態方法:
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));}
靜態變數sThreadLocal是範型類ThreadLocal<Looper>的執行個體,用於儲存線程與其Looper之間的映射關係:sThreadLocal以自身為key,將Looper執行個體放入當前線程的ThreadLocalMap中(欄位名為threadlocals,ThreadLocalMap底層是通過hash表實現的)。由於任何線程存放Looper都是以sThreadLocal為key,所以任意線程最多隻能有一個Looper。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue();}
Looper迴圈
準備完成之後,通過調用Looper.loop()進入looper迴圈。Looper在死迴圈中,不斷從MessageQueue中擷取訊息,交給Handler的dispatchMessage進行處理。loop函數的關鍵代碼是黃色背景標記的地區:
1 public static void loop() { 2 final Looper me = myLooper(); 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); 5 } 6 final MessageQueue queue = me.mQueue; 7 8 // Make sure the identity of this thread is that of the local process, 9 // and keep track of what that identity token actually is.10 Binder.clearCallingIdentity();11 final long ident = Binder.clearCallingIdentity();12 13 for (;;) {14 Message msg = queue.next(); // might block15 if (msg == null) {16 // No message indicates that the message queue is quitting.17 return;18 }19 20 // This must be in a local variable, in case a UI event sets the logger21 final Printer logging = me.mLogging;22 if (logging != null) {23 logging.println(">>>>> Dispatching to " + msg.target + " " +24 msg.callback + ": " + msg.what);25 }26 27 final long traceTag = me.mTraceTag;28 if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {29 Trace.traceBegin(traceTag, msg.target.getTraceName(msg));30 }31 try {32 msg.target.dispatchMessage(msg);33 } finally {34 if (traceTag != 0) {35 Trace.traceEnd(traceTag);36 }37 }38 39 if (logging != null) {40 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);41 }42 43 // Make sure that during the course of dispatching the44 // identity of the thread wasn‘t corrupted.45 final long newIdent = Binder.clearCallingIdentity();46 if (ident != newIdent) {47 Log.wtf(TAG, "Thread identity changed from 0x"48 + Long.toHexString(ident) + " to 0x"49 + Long.toHexString(newIdent) + " while dispatching to "50 + msg.target.getClass().getName() + " "51 + msg.callback + " what=" + msg.what);52 }53 54 msg.recycleUnchecked();55 }56 }
每個Message被處理完之後,會被自動回收,放回Message池中。
Looper退出
通過調用quit或者quitSafely退出Looper迴圈。底層是調用MessageQueue的quit函數實現:
1 void quit(boolean safe) { 2 if (!mQuitAllowed) { 3 throw new IllegalStateException("Main thread not allowed to quit."); 4 } 5 6 synchronized (this) { 7 if (mQuitting) { 8 return; 9 }10 mQuitting = true;11 12 if (safe) {13 removeAllFutureMessagesLocked();14 } else {15 removeAllMessagesLocked();16 }17 18 // We can assume mPtr != 0 because mQuitting was previously false.19 nativeWake(mPtr);20 }21 }
quit調用removeAllMessageLocked,該函數會直接移除MessageQueue中所有尚未處理的Message;quitSafely調用removeAllFutureMessageLocked,該函數只會移除執行時刻晚於當前時刻的Message(即,Message.when > now)。
Android源碼學習(2) Handler之Looper