Adnroid進階:Handler、Looper、Message、MessageQueue基礎流程分析
Looper
(先分析這個是因為能夠引出四者的關係) 在Looper中,維持一個Thread
物件以及MessageQueue
,通過Looper的建構函式我們可以知道:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed);//傳入的引數代表這個Queue是否能夠被退出 mThread = Thread.currentThread(); }
Looper
在建構函式裡幹了兩件事情:
- 將執行緒物件指向了建立
Looper
的執行緒 - 建立了一個新的
MessageQueue
分析完建構函式之後,接下來我們主要分析兩個方法:
looper.loop()
looper.prepare()
looper.loop()(在當前執行緒啟動一個Message loop機制,此段程式碼將直接分析出Looper、Handler、Message、MessageQueue的關係)
public static void loop() { final Looper me = myLooper();//獲得當前執行緒繫結的Looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//獲得與Looper繫結的MessageQueue // 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(); //進入死迴圈,不斷地去取物件,分發物件到Handler中消費 for (;;) { Message msg = queue.next(); // 不斷的取下一個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); } //在這裡,開始分發Message了 //至於這個target是神馬?什麼時候被賦值的? //我們一會分析Handler的時候就會講到 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); } //當分發完Message之後,當然要標記將該Message標記為 *正在使用* 啦 msg.recycleUnchecked(); } }
分析了上面的原始碼,我們可以意識到,最重要的方法是:
queue.next()
msg.target.dispatchMessage(msg)
msg.recycleUnchecked()
其實Looper中最重要的部分都是由Message
、MessageQueue
組成的有木有!這段最重要的程式碼中涉及到了四個物件,他們與彼此的關係如下:
MessageQueue
:裝食物的容器Message
:被裝的食物Handler
(msg.target實際上就是Handler
):食物的消費者Looper
:負責分發食物的人
looper.prepare()
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//在當前執行緒繫結一個Looper
sThreadLocal.set(new Looper(quitAllowed));
}
以上程式碼只做了兩件事情:
- 判斷當前執行緒有木有
Looper
,如果有則丟擲異常(在這裡我們就可以知道,Android規定一個執行緒只能夠擁有一個與自己關聯的Looper
)。 - 如果沒有的話,那麼就設定一個新的
Looper
到當前執行緒。
Handler
由於我們使用Handler的通常性的第一步是:
Handler handler = new Handler(){
//你們有沒有很好奇這個方法是在哪裡被回撥的?
//我也是!所以接下來會分析到喲!
@Override
public void handleMessage(Message msg) {
//Handler your Message
}
};
所以我們先來分析Handler
的構造方法
//空引數的構造方法與之對應,這裡只給出主要的程式碼,具體大家可以到原始碼中檢視
public Handler(Callback callback, boolean async) {
//列印記憶體洩露提醒log
....
//獲取與建立Handler執行緒繫結的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//獲取與Looper繫結的MessageQueue
//因為一個Looper就只有一個MessageQueue,也就是與當前執行緒繫結的MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
帶上問題:
Looper.loop()
死迴圈中的msg.target
是什麼時候被賦值的?handler.handleMessage(msg)
在什麼時候被回撥的?
A1:Looper.loop()
死迴圈中的msg.target
是什麼時候被賦值的?
要分析這個問題,很自然的我們想到從傳送訊息開始,無論是handler.sendMessage(msg)
還是handler.sendEmptyMessage(what)
,我們最終都可以追溯到以下方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//引用Handler中的MessageQueue
//這個MessageQueue就是建立Looper時被建立的MessageQueue
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//將新來的Message加入到MessageQueue中
return enqueueMessage(queue, msg, uptimeMillis);
}
我們接下來分析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);
}
A2:handler.handleMessage(msg)
在什麼時候被回撥的?
通過以上的分析,我們很明確的知道Message
中的target
是在什麼時候被賦值的了,我們先來分析在Looper.loop()
中出現過的過的dispatchMessage(msg)
方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//看到這個大寫加粗的方法呼叫沒!
**handleMessage(msg);**
}
}
加上以上分析,我們將之前分析結果串起來,就可以知道了某些東西: Looper.loop()
不斷地獲取MessageQueue
中的Message
,然後呼叫與Message
繫結的Handler
物件的dispatchMessage
方法,最後,我們看到了handleMessage
就在dispatchMessage
方法裡被呼叫的。
通過以上的分析,我們可以很清晰的知道Handler、Looper、Message、MessageQueue這四者的關係以及如何合作的了。
總結:
當我們呼叫handler.sendMessage(msg)
方法傳送一個Message
時,實際上這個Message
是傳送到與當前執行緒繫結的一個MessageQueue
中,然後與當前執行緒繫結的Looper
將會不斷的從MessageQueue
中取出新的Message
,呼叫msg.target.dispathMessage(msg)
方法將訊息分發到與Message
繫結的handler.handleMessage()
方法中。
一個Thread
對應多個Handler
一個Thread
對應一個Looper
和MessageQueue
,Handler
與Thread
共享Looper
和MessageQueue
。 Message
只是訊息的載體,將會被髮送到與執行緒繫結的唯一的MessageQueue
中,並且被與執行緒繫結的唯一的Looper
分發,被與其自身繫結的Handler
消費。