Android訊息機制剖析—Looper篇
阿新 • • 發佈:2019-02-13
本篇文章在android6.0基礎上分析。
Looper在訊息機制中扮演的角色是創造無限迴圈從Messagequeue中取得訊息然後分發。
一、Looper的建立
只要呼叫Looper.prepare()方法之後,然後再Looper.loop()即可,這裡兩個方法都是static方法,表面沒有任何Looper物件的參與,具體如何
先來看下prepare()這個方法:
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");//限制Looper.prepare()只能呼叫一次 } sThreadLocal.set(new Looper(quitAllowed));//這裡才是Looper物件的建立,放入sThreadLocal中 }
<pre name="code" class="java"> private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//創造了Messagequeue
mThread = Thread.currentThread();
}
程式碼中提到了sThreadLocal變數,型別為ThreadLocal,ThreadLocal的特殊作用在:可以多個執行緒共享,但set和get的作用域都是執行緒內的。例如thread-1和thread-2兩個執行緒都呼叫了Loop.prepare(),使用的ThreadLocal是同一個物件,但set()放入的Looper是分別屬於各自的。
二、Looper的loop()
先看原始碼,核心的地方被我加了註釋。這個Loop是訊息機制的核心所在,尤其是for(;;)這個死迴圈;上面程式碼關注四個點: (1)呼叫myLooper來判斷是否已經用Looper.prepare()建立了Looper物件(ThreadLocal儲存) (2)Loop迴圈每次都會從MessageQueue中獲取一個Message(next()方法),如果沒有則執行緒阻塞。 (3)如果獲取了一個Message,則呼叫target(Hanlder)的dispatchMessage方法來分派處理這個Message。 (4)最後呼叫msg.recycleUnchecked(),來格式化這個Message,重新進入訊息池;public static void loop() { final Looper me = myLooper();//從ThreadLocal中獲取本執行緒的Looper物件,這個物件是用Looper.prepare建立的 if (me == null) {//如果沒有Looper.prepare,就呼叫了loop就會丟擲下面的異常 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 (;;) {//最重要的就是這個死迴圈,4.0之前是while(true) Message msg = queue.next(); // might block,MessageQueue沒有訊息,執行next()就會執行緒阻塞,直到有訊息為止。 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(); } }
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//如果是執行緒thread-1呼叫,則獲得的thread-1的Looper,如果是thread-2調動,獲得的是thread-2的looper。
}