源碼分析Android Handler是如何實現線程間通信的
Handler作為Android消息通信的基礎,它的使用是每一個開發者都必須掌握的。開發者從一開始就被告知必須在主線程中進行UI操作。但Handler是如何實現線程間通信的呢?本文將從源碼中分析Handler的消息通信機制。
0x00 Handler使用
首先看看我們平時是如何使用的Handler的。先看看以下代碼
//定義Handler
Handler mHandler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case UPDATE_UI:
updateUI(msg);
break;
}
}
};
class MyThread extends Thread{
public void run(){
//do same work!
...
//send message
Message msg = mHandler.obtainMessage(UPDATE_UI);
mHandler.sendMessage(msg);
}
}
private void updateUI(Message msg){
//update UI
}
在子線程中sendMessage(Message)發送消息,然后在Handler的handleMessage(Message)接收消息,執行更新UI操作。那么Handler是如何把消息從MyThread傳遞到MainThread中來呢?我們從sendMessage()開始慢慢揭開它的面紗。
0x01 sendMessage(Message)
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()方法最后都走到enqueueMessage()這個方法,一開始就把當前Handler實例賦給了Message.target的屬性里面,后面可以知道這個target是用來執行處理函數回調的。
enqueueMessage方法是把Message信息放入到一個MessageQueue的隊列中。顧名思義MessageQueue就是消息隊列。從sendMessageAtTime()方法知道這個MessageQueue是Handler中的一個成員。它是在Handler的構造函數中通過Loopger對象來初始化的。
0x02 Handler構造函數
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
這時候我們腦海知道創建Handler的時候,同時也創建了Looper實例和MessageQueue引用(MessageQueue對象其實是在Looper中構造的)。Looper是何物呢?簡單地說就是消息循環,這個我們稍后會分析。
0x03 enqueueMessage(MessageQueue)
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(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
}
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;
}
在MessageQueue中可以看到這個入列方法中有一個for循環就是把當前的需要處理Message放到隊列的合適位置。因為需要處理的Message對象都有一個開始處理的時間when,這個隊列是按照when排序的。
至此,Handler調用sendMessage()方法后就把Message消息通過enqueueMessage()插入MessageQueue隊列中。
而這個MessageQueue是在Looper中維護的。
0x04 prepare()創建Looper
在0x02中我們知道創建Handler時就使用靜態方法Looper.myLooper()得到當前線程的Looper對象。
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal是一個ThreadLocal類型的靜態變量。什么時候會把Looper對象放在sThreadLocal中呢?通過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));
}
繼續翻閱源碼知道Looper在構造函數中創建MessageQueue對象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
調用prepare()方法將一個Looper對象放在了靜態的ThreadLocal對象中。這個是一個與線程綁定的對象,且在內存中僅保存了一份引用。
使用ThreadLocal對象這一點非常巧妙,也非常重要,這是線程間通信的基礎。即在線程中調用prepare()時就在該線程中綁定了Looper對象,而Looper對象中擁有MessageQueue引用。所以每個線程都有一個消息隊列。
這樣Handler、Looper、MessageQueue這幾個類關系大概就可以畫出來了。

0x05 啟動循環loop()
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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 (;;) {
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
//執行處理消息的回調
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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()方法中有一個無限循環,不停地讀取調用MessageQueue的next()方法。當next()沒有返回時就阻塞在這里。當獲取到MessageQueue中的消息時,就執行了處理消息的回調函數msg.target.dispatchMessage(msg)。
前面0x01分析我們知道msg.target是在Handler中的enqueueMessage()進行賦值,即它指向當前的Handler實例。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
執行msg.target.dispatchMessage(msg)后便走到了以下流程
/** * Handle system messages here. */
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這里就是回調handleMessage(msg)函數處理消息的地方。Handler負責將Message入列,Looper則負責循環從MessageQueue中取出需要處理的Message並交由Handler來處理。
0x06 啟動主線程的消息循環
我們知道通過靜態方法Looper.prepare()創建了綁定當前線程的Looper對象,而通過loop()啟動一個循環不停地讀取隊列中Message。但是Android系統是什么時候啟動了主線程的消息循環呢?
要理解這一點就必須進入Android應用程序的入口ActivityThread的main方法。
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看出main方法中先后執行了Looper.prepareMainLooper()方法和Looper.loop()方法。正常情況下main方法不會退出,只有loop()方法發生異常后將會拋出RuntimeException。
0x07 Looper.prepareMainLooper()
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepareMainLooper()方法其實是調用了prepare()方法。
當我們啟動應用時系統就調用了prepareMainLooper()並在主線程中綁定了一個Looper對象。
這時候我們回過來看看一開始的Handler使用方式。在主線程中我們創建了Handler對象,在Handler構造函數中初始化了Looper(即獲取到了綁定在主線程中的Looper對象)。當在子線程MyThread中通過mHandler.sendMessage(msg)方法發送一個消息時就把Message放在與主線程綁定的MessageQueue中。這樣在子線程中使用Handler就實現了消息的通信。
可以簡單的使用以下類圖表示,每個線程都由一個Handler,每個Handler都是與當前所在線程的Looper綁定。

0x08 主線程是否會阻塞
在0x06中知道在ActivityThead的main方法中啟動了一個死循環。那主線程是不是就一直阻塞在這里呢?其實不然。可以看到ActivityThread類里面有一個自定義的Handler對象mH,在這里對象中handleMessage()回調中定義了Activity的各種交互如管理Activity生命周期,啟動service,顯示window等,都是通過Handler進行處理的。同時可以看出只有當應用退出EXIT_APPLICATION之后才回調用Looper.quit()停止消息循環。
public void handleMessage(Message msg) {
...
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
case PAUSE_ACTIVITY: {
...
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
...
} break;
...
case SHOW_WINDOW:
...
handleWindowVisibility((IBinder)msg.obj, true);
...
break;
...
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
...
}
...
}
0x09 總結
當創建Handler時將通過ThreadLocal在當前線程綁定一個Looper對象,而Looper持有MessageQueue對象。執行Handler.sendMessage(Message)方法將一個待處理的Message插入到MessageQueue中,這時候通過Looper.loop()方法獲取到隊列中Message,然后再交由Handler.handleMessage(Message)來處理。
微信關注我們,可以獲取更多

