【原始碼解讀】Handler訊息機制流程分析
之前看《藝術探索》大致瞭解了Android訊息機制的原理,也總結了筆記,但總感覺理解的不夠徹底,之後把原始碼和之前的筆記又看了一遍,算是基本通了,將基本邏輯記錄在此,重在分析流程,不分析具體細節原理。
這裡以主執行緒為例,Handler訊息機制的完整過程如下:
1.執行緒建立Looper, 同時初始化MessageQuene和Thread物件,開啟迴圈
在ActivityThread的main方法中,會首先建立主執行緒的Handler,因此我們在主執行緒中是可以建立Handler物件而不需要考慮Looper問題的。
public static void main(String[] args) {
//程式碼省略...
Looper.prepareMainLooper();
Looper.loop();
}
最終通過prepare方法建立Looper物件並使用ThreadLocal進行儲存,原始碼如下:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared." );
}
sMainLooper = myLooper();
}
}
//最終呼叫該方法建立Looer物件,因為是主執行緒所以這裡的引數為false
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的建構函式中會同時建立其MessageQuene和Thread物件.這樣就建立好了我們需要的Looper物件以及MessageQueue和Thread物件,並通過Looper.loop()方法開啟無限迴圈
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.建立Handler物件
這裡最常使用的方式就是新建一個Handler物件並傳遞一個CallBack物件,當然還有其他的構造方法,這裡不作贅述
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what){
case 1:
String obj = (String) msg.obj;
Log.i(TAG, obj);
break;
}
return true;
}
});
3.sendMessage或者post一個Runnable物件
使用建立好的handler物件傳遞訊息,無論是sendMessage還是post一個Runnable物件,最終會呼叫到
sendMessageAtTime,之後會呼叫MessageQuene物件的enqueueMessage()方法將訊息加入到佇列中
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);
}
//設定msg.target為當前Handler物件,並將訊息儲存進訊息佇列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
4.在loop方法中,呼叫handler的dispatcher進行分發.
在prepare好Looper之後,便呼叫了loop方法,其原始碼如下
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 (;;) {
/**
* 呼叫MessageQuene的next方法獲取訊息物件,如果沒有訊息則終止迴圈
*/
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就是在enqueueMessage方法中設定好的Handler物件,
* 呼叫dispatchMessage進行訊息分發
*/
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();
}
}
loop內部也是無限迴圈,去呼叫MessageQuene的next方法,如果有訊息則拿到訊息物件並通過Handler物件進行分發進行分發
5.dispatchMessage對訊息進行分發,根據傳遞的訊息選擇不同的呼叫,具體如下
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//檢查Message的callback是否為空,不為空則呼叫handleCallback
//當我們使用post提交一個Runnable物件的時候回撥用該方法,最終執行我們
//的Runnable物件的run方法中的內容
handleCallback(msg);
} else {
if (mCallback != null) {
//當使用sendMessage傳送資訊並建立了CallBack物件時呼叫
//這就是我們最常見的使用方法,最終會呼叫到我們重寫的handleMessaeg方法
if (mCallback.handleMessage(msg)) {
return;
}
}
//呼叫Handler自己的handleMessage,方面裡面為空,啥都不幹
handleMessage(msg);
}
}
簡單來說,在子執行緒通過主執行緒的Handler物件傳送資料時,最終會呼叫到Handler的handleMessage方法進行處理,因為Handler處於主執行緒,那麼此時操作就從子執行緒切換到了主執行緒,從而執行緒間的通訊。
OK,以上就是整個Handler訊息機制的建立處理流程。