本文主要是梳理一下 Handler 的相關知識,不會每個點都講的很細,關鍵在于每個知識點的融匯貫通。
一、Android 消息機制工作的幾點要素:
1、消息循環(huán) Looper
2、消息隊列 MessageQueue
3、發(fā)送消息、處理消息 Handler
4、消息實體 Message
Handler 是每個 Android 開發(fā)者在一開始就會接觸到的,上面提到的幾點要素也是我們牢記在心的,但其實在一開始我沒有去好好讀源碼的情況下,雖然記住了這幾點,但根本沒理解消息機制,只是會用sendMessage去發(fā)消息,handleMessage去處理消息,后來我也陸陸續(xù)續(xù)讀了幾次 Handler 的源碼,直到最近我想整理下消息機制的內(nèi)容,我才真正體會到消息機制的設計思想,并且把消息機制和一些我們不是經(jīng)常使用的工具,比如IntentService、HandlerThread、LocalBroadcastManager所聯(lián)系起來,讓我深刻的感受到消息機制在 Android 系統(tǒng)中的無處不在。在我看來,要理解消息機制,一定要理清楚線程的概念。下面我們就從先來看一下主線程(UI 線程)中的消息機制。
當應用程序啟動初始化進程時,會加載ActivityThread 這個類,來看一下main函數(shù)中是如何初始化主線程中的消息機制的:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
...
}
通過上面的源碼我們大概就能知道要想讓消息工作起來,主要有三個步驟,第一調(diào)用Looper.prepare,第二調(diào)用new Handler(),最后調(diào)用Looper.loop()讓整個消息機制工作起來。
看一下Looper.prepare()的源碼:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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");
}
sThreadLocal.set(new Looper(quitAllowed));
}
代碼比較短,這里涉及到ThreadLocal這個類,簡單說一下這個類,ThreadLocal中保存的變量,作用域只在當前線程中,我們看一下異常的說明就知道了Only one Looper may be created per thread:每個線程只能有一個 Looper。
接下來看一下Handler的構造函數(shù):
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
...
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;
}
我們看到有個mLooper變量會讀取當前線程中的Looper,如果為空,也會拋出異常。
從上面兩部分的源碼,就能想到,為什么平時我們在UI線程中直接執(zhí)行new Handler()是可以的,而在子線程中執(zhí)行會報錯,因為在應用啟動時,主線程中的Looper已經(jīng)初始化好了。
最后一步就是Looper.loop()函數(shù)了,這步的工作就是不斷從MessageQueue中取消息,取不到就阻塞,取到就分發(fā)給Handler,這部分代碼的細節(jié),同學們自己去挖掘。
二、主線程的Handler分析
來看一下在ActivityThread中初始化的Handler:
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
...
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
}
這部分代碼包含了很多的常量定義,從命名上我們可以感覺出來 ,好像都是和生命周期相關的,下面是一個handlerMessage來處理消息,由此我們就知道了為什么在Activity、Service、BroadCast這些組件的生命周期函數(shù)中,不能做耗時的任務,因為全是在主線程上運行的,耗時任務會導致ANR。之所以在這些函數(shù)中沒法執(zhí)行耗時任務,就誕生了一系列的工具類:IntentService、HandlerThread、LocalBroadcastManager。簡單的看下源碼你就會發(fā)現(xiàn):
1、
HandlerThread是一個自帶Looper的線程,通過這個Looper可以創(chuàng)建Handler來實現(xiàn)子線程與主線程收發(fā)消息;
2、IntentService內(nèi)部實現(xiàn)了HandlerThread來執(zhí)行耗時任務,執(zhí)行完成自動銷毀Service;
3、LocalBroadcastManager被稱為本地廣播,之所以這么稱呼,因為在其內(nèi)部有主線程的Looper,所以可以給主線程發(fā)送任意消息,這個工具通常用作應用內(nèi)的通信。
通過源碼我們可以看到,消息機制在 Android 系統(tǒng)中的無處不在,同學們挖掘到更多使用Handler的地方,歡迎留言討論。
延伸閱讀:
1、理解Java中的ThreadLocal
2、詳解 Android 中的 HandlerThread
3、Android IntentService完全解析 當Service遇到Handler
4、LocalBroadcastManager 的實現(xiàn)原理