線程通信、ActivityThread及Thread類是理解Android線程管理的關(guān)鍵。
線程,作為CPU調(diào)度資源的基本單位,在Android等針對(duì)嵌入式設(shè)備的操作系統(tǒng)中,有著非常重要和基礎(chǔ)的作用。本小節(jié)主要從以下三個(gè)方面進(jìn)行分析:
- Android線程管理(一)——線程通信
- Android線程管理(二)——ActivityThread
- Android線程管理(三)——Thread
一、Handler、MessageQueue、Message及Looper四者的關(guān)系
在開(kāi)發(fā)Android多線程應(yīng)用時(shí),Handler、MessageQueue、Message及Looper是老生常談的話題。但想徹底理清它們之間的關(guān)系,卻需要深入的研究下它們各自的實(shí)現(xiàn)才行。首先,給出一張它們之間的關(guān)系圖:

- Looper依賴于MessageQueue和Thread,因?yàn)槊總€(gè)Thread只對(duì)應(yīng)一個(gè)Looper,每個(gè)Looper只對(duì)應(yīng)一個(gè)MessageQueue。
- MessageQueue依賴于Message,每個(gè)MessageQueue對(duì)應(yīng)多個(gè)Message。即Message被壓入MessageQueue中,形成一個(gè)Message集合。
- Message依賴于Handler進(jìn)行處理,且每個(gè)Message最多指定一個(gè)Handler來(lái)處理。Handler依賴于MessageQueue、Looper及Callback。
從運(yùn)行機(jī)制來(lái)看,Handler將Message壓入MessageQueue,Looper不斷從MessageQueue中取出Message(當(dāng)MessageQueue為空時(shí),進(jìn)入休眠狀態(tài)),其target handler則進(jìn)行消息處理。因此,要徹底弄清Android的線程通信機(jī)制,需要了解以下三個(gè)問(wèn)題:
- Handler的消息分發(fā)、處理流程
- MessageQueue的屬性及操作
- Looper的工作原理
1.1 Handler的消息分發(fā)、處理流程
Handler主要完成Message的入隊(duì)(MessageQueue)和處理,下面將通過(guò)Handler的源碼分析其消息分發(fā)、處理流程。首先,來(lái)看下Handler類的方法列表:

從上圖中可以看出,Handler類核心的方法包括:1)構(gòu)造器;2)分發(fā)消息;3)處理消息;4)post發(fā)送消息;5)send發(fā)送消息;6)remove消息和回調(diào)。
首先,從構(gòu)造方法來(lái)看,構(gòu)造器的多態(tài)最終通過(guò)調(diào)用如下方法實(shí)現(xiàn),即將實(shí)參賦值給Handler類的內(nèi)部域。
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
其次,消息的入隊(duì)是通過(guò)post方法和send方法來(lái)實(shí)現(xiàn)的。
public final boolean postAtTime(Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
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);
}
兩者的區(qū)別在于參數(shù)類型不同,post方法傳入的實(shí)例對(duì)象實(shí)現(xiàn)了Runnable接口,然后在內(nèi)部通過(guò)getPostMessage方法將其轉(zhuǎn)換為Message,最終通過(guò)send方法發(fā)出;send方法傳入的實(shí)例對(duì)象為Message類型,在實(shí)現(xiàn)中,將Message壓入MessageQueue。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
通過(guò)Handler將Message壓入MessageQueue之后,Looper將其輪詢后交由Message的target handler處理。Handler首先會(huì)對(duì)消息進(jìn)行分發(fā)。首先判斷Message的回調(diào)處理接口Callback是否為null,不為null則調(diào)用該Callback進(jìn)行處理;否判斷Handler的回調(diào)接口mCallback是否為null,不為null則調(diào)用該Callback進(jìn)行處理;如果上述Callback均為null,則調(diào)用handleMessage方法處理。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleMessage方法在Handler的子類中必須實(shí)現(xiàn)。即消息具體的處理交由應(yīng)用軟件實(shí)現(xiàn)。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
回到Activity(Fragment),在Handler的子類中實(shí)現(xiàn)handleMessage方法。這里需要注意一個(gè)內(nèi)存泄露的問(wèn)題,比較下述兩種實(shí)現(xiàn)方式,第一種直接定義Handler的實(shí)現(xiàn),第二種通過(guò)靜態(tài)內(nèi)部類繼承Handler,定義繼承類的實(shí)例。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 根據(jù)msg調(diào)用Activity的方法
}
};
static class MyHandler extends Handler {
WeakReference<DemoActivity> mActivity;
public MyHandler(DemoActivity demoActivity) {
mActivity = new WeakReference<DemoActivity>(demoActivity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
DemoActivity theActivity = mActivity.get();
// 根據(jù)msg調(diào)用theActivity的方法
}
不繞彎子,直接說(shuō)明為什么第一種方式會(huì)引起內(nèi)存泄露,而第二種不會(huì)。
在第一種方式中,mHandler通過(guò)匿名內(nèi)部類方式實(shí)例化,在Java中,內(nèi)部類會(huì)強(qiáng)持有外部類的引用(handleMessage方法中可以直接調(diào)用Activity的方法),在外部Activity調(diào)用onDestroy()方法之后,如果Handler的MessageQueue依然有未處理的消息,那么由于Handler持有Activity的引用導(dǎo)致Activity無(wú)法被系統(tǒng)GC回收,從而引起內(nèi)存泄露。
在第二種方式中,首先繼承Handler定義靜態(tài)內(nèi)部類,由于MyHandler為靜態(tài)類,即使定義在Activity的內(nèi)部,也與Activity沒(méi)有邏輯上的聯(lián)系,即不會(huì)持有外部Activity的引用;其次,在靜態(tài)類內(nèi)部,定義外部Activity的弱引用,弱引用在系統(tǒng)資源緊張時(shí)會(huì)被系統(tǒng)優(yōu)先回收。最后,在handleMessage()方法中,通過(guò)WeakReference的get方法獲取外部Activity的引用,如果該弱引用已被回收,則get方法返回null。
struct GcSpec {
/* If true, only the application heap is threatened. */
bool isPartial;
/* If true, the trace is run concurrently with the mutator. */
bool isConcurrent;
/* Toggles for the soft reference clearing policy. */
bool doPreserve;
/* A name for this garbage collection mode. */
const char *reason;
};
這段代碼定義在dalvik/vm/alloc/Heap.h中,其中doPreserve為true時(shí),表示在執(zhí)行GC的過(guò)程中,不回收軟引用引用的對(duì)象;為false時(shí),表示在執(zhí)行GC的過(guò)程中,回收軟引用引用的對(duì)象。
最后,使用Handler的過(guò)程中,還需要注意一點(diǎn),在前面的方法列表圖中已經(jīng)提到。為避免Activity調(diào)用onDestroy后,Handler的MessageQueue中仍存在Message,一般會(huì)在onDestroy中調(diào)用removeCallbacksAndMessages()方法。
@Override
protected void onDestroy() {
super.onDestroy();
// 清空Message隊(duì)列
myHandler.removeCallbacksAndMessages(null);
}
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
removeCallbacksAndMessages()方法會(huì)移除obj為token的由post發(fā)送的callback和send發(fā)送的message,當(dāng)token為null時(shí),會(huì)移除所有callback和message。
1.2 MessageQueue的屬性及操作
MessageQueue,消息隊(duì)列,其屬性與常規(guī)隊(duì)列相似,包括入隊(duì)、出隊(duì)等,這里簡(jiǎn)要介紹一下MessageQueue的實(shí)現(xiàn)。
首先,MessageQueue新建隊(duì)列的工作是通過(guò)在其構(gòu)造器中調(diào)用本地方法nativeInit實(shí)現(xiàn)的。nativeInit會(huì)創(chuàng)建NativeMessageQueue對(duì)象,然后賦值給MessageQueue成員變量mPtr。mPtr是int類型數(shù)據(jù),代表NativeMessageQueue的內(nèi)存指針。
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
其次,Message入隊(duì)的通過(guò)enqueueMessage方法實(shí)現(xiàn)。首先檢查message是否符合入隊(duì)要求(是否正在使用,target handler是否為null),符合要求后通過(guò)設(shè)置prev.next = msg隊(duì)列的指針完成入隊(duì)操作。
boolean enqueueMessage(Message msg, long when);
再次,出隊(duì)是通過(guò)next()方法完成的。涉及到同步、鎖等問(wèn)題,這里不詳細(xì)展開(kāi)了。
再次,刪除元素有兩個(gè)實(shí)現(xiàn)。即分別通過(guò)p.callback == r和p.what == what來(lái)進(jìn)行消息識(shí)別。
void removeMessages(Handler h, int what, Object object);
void removeMessages(Handler h, Runnable r, Object object);
最后,銷毀隊(duì)列和創(chuàng)建隊(duì)列一樣,是通過(guò)本地函數(shù)完成的。傳入的參數(shù)為MessageQueue的內(nèi)存指針。
private native static void nativeDestroy(int ptr);
1.3 Looper的工作原理
Looper是線程通信的關(guān)鍵,正是因?yàn)長(zhǎng)ooper,整個(gè)線程通信機(jī)制才真正實(shí)現(xiàn)“通”。
在應(yīng)用開(kāi)發(fā)過(guò)程中,一般當(dāng)主線程需要傳遞消息給用戶自定義線程時(shí),會(huì)在自定義線程中定義Handler進(jìn)行消息處理,并在Handler實(shí)現(xiàn)的前后分別調(diào)用Looper的prepare()方法和loop()方法。大致實(shí)現(xiàn)如下:
new Thread(new Runnable() {
private Handler mHandler;
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
});
這里重點(diǎn)說(shuō)明prepare()方法和loop()方法,實(shí)際項(xiàng)目中不建議定義匿名線程。
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));
}
可以看出,prepare方法的重點(diǎn)是sThreadLocal變量,sThreadLocal變量是什么呢?
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal實(shí)現(xiàn)了線程本地存儲(chǔ)。簡(jiǎn)單看一下它的類注解文檔,ThreadLocal是一種特殊的全局變量,全局性在于它存儲(chǔ)于自己所在線程相關(guān)的數(shù)據(jù),而其他線程無(wú)法訪問(wèn)。
/**
* Implements a thread-local storage, that is, a variable for which each thread
* has its own value. All threads share the same {@code ThreadLocal} object,
* but each sees a different value when accessing it, and changes made by one
* thread do not affect the other threads. The implementation supports
* {@code null} values.
*
* @see java.lang.Thread
* @author Bob Lee
*/
public class ThreadLocal<T> {
}
回到prepare方法中,sThreadLocal添加了一個(gè)針對(duì)當(dāng)前線程的Looper對(duì)象。并且prepare方法只能調(diào)用一次,否則會(huì)拋出運(yùn)行時(shí)異常。
初始化完畢之后,Handler通過(guò)post和send方法如何保證消息投遞到Looper所持有的MessageQueue中呢?其實(shí),MessageQueue是Handler和Looper的橋梁。在前面Handler章節(jié)中提到Handler的初始化方法,Handler的mLooper對(duì)象是通過(guò)Looper的靜態(tài)方法myLooper()獲取的,而myLooper()是通過(guò)調(diào)用sThreadLocal.get()來(lái)得到的,即Handler的mLooper就是當(dāng)前線程的Looper對(duì)象,Handler的mQueue就是mLooper.mQueue。
……
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
……
public static Looper myLooper() {
return sThreadLocal.get();
}