轉(zhuǎn)載請(qǐng)注明文章出處LooperJing担忧!
Android的消息機(jī)制我覺(jué)得是每一個(gè)弄Android開(kāi)發(fā)的人都要弄懂得問(wèn)題,也有很多人對(duì)它進(jìn)行研究,Android的消息機(jī)制的重要性不強(qiáng)調(diào),但是覺(jué)得自己對(duì)Android的消息機(jī)制了解不深刻锈颗,所以決定深入源碼,寫(xiě)下三篇博客以記之咪惠。因?yàn)镸essage全局池和ThreadLocal對(duì)Android的消息機(jī)制理解很重要击吱,附上前兩篇的博客地址。
Android源碼解析Handler系列第(一)篇 --- Message全局池
Android源碼解析Handler系列第(二)篇 --- ThreadLocal詳解
先來(lái)一張圖感受一下遥昧,下面這張圖基本說(shuō)明了Android的消息機(jī)制的工作流程覆醇。
不看別的,主要涉及的類(lèi)有Thread炭臭,Looper永脓,MessageQueue,Handler,其實(shí)還有一個(gè)ThreadLocal,這些類(lèi)都是整套消息機(jī)制中很關(guān)鍵的類(lèi)鞋仍,下面我們正式分析這套機(jī)制是怎么運(yùn)行的常摧。
要分析這套機(jī)制是怎么運(yùn)行的,要首先從應(yīng)用程序的入口說(shuō)起威创,Android應(yīng)用程序的入口是ActivityThread類(lèi)的main方法排宰。下面是main方法中的相關(guān)代碼。
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
//創(chuàng)建UI線(xiàn)程所需要的Looper,Looper有何用那婉,后面再說(shuō)
Looper.prepareMainLooper();
//這里最終啟動(dòng)應(yīng)用程序
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//執(zhí)行消息循環(huán)
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
注意到板甘,入口函數(shù)的最后一行代碼是Looper調(diào)用了靜態(tài)方法Looper. loop(),而這個(gè)loop是死循環(huán),按照正常的理解详炬,在主線(xiàn)程中執(zhí)行死循環(huán)盐类,那么就不能做其他任務(wù)了,比如按鈕事件的觸發(fā)呛谜,動(dòng)畫(huà)的播放等在跳。但是反過(guò)來(lái)想一想,如果這不是死循環(huán)隐岛,那么最后一行代碼執(zhí)行完猫妙,應(yīng)用程序不就跑完了嘛。并且這行代碼也只能放在main的最后一句聚凹,如果放在前面割坠,后面的程序就沒(méi)有辦法進(jìn)行了。
好滴妒牙, Looper.loop()是執(zhí)行消息循環(huán)彼哼,去這里看個(gè)究竟。
/**
* 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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
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();
}
}
代碼比較長(zhǎng)湘今,但是真的比較容易理解的敢朱,第一句執(zhí)行final Looper me = myLooper()獲取一個(gè)Looper對(duì)象,怎么獲取的呢?在myLooper中涉及到了ThreadLocal,對(duì)ThreadLocal不了解的拴签,看我的第二篇博客孝常。
/**
* 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.get()返回了NULl,那么程序就會(huì) throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 蚓哩,尼瑪构灸,如果主線(xiàn)程在這都拋了異常,那還玩毛線(xiàn)杖剪,所以必然有sThreadLocal.set()冻押。回到剛才盛嘿,在執(zhí)行消息循環(huán)Looper.loop之前洛巢,有一句關(guān)鍵的代碼, Looper.prepareMainLooper()次兆,這句話(huà)可以創(chuàng)建UI線(xiàn)程所需要的Looper稿茉,跟蹤進(jìn)去。
public static void prepareMainLooper() {
//代碼在下面
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//從sThreadLocal中獲取Looper芥炭,系統(tǒng)默認(rèn)給我們創(chuàng)建了sMainLooper
sMainLooper = myLooper();
}
}
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));
}
在sThreadLocal.get() 為NULL的情況下漓库,直接以餓漢式的方式new了一個(gè)Looper, 調(diào)用sThreadLocal的set方法,這一步园蝠,通過(guò)sThreadLocal渺蒿,其實(shí)是將Looper與當(dāng)前線(xiàn)程(UI線(xiàn)程)做了關(guān)聯(lián), 也就是說(shuō)上面創(chuàng)建的Looper對(duì)象me只能被主線(xiàn)程所訪問(wèn)彪薛,其他線(xiàn)程訪問(wèn)不了C啊!善延!少态,這就是ThreadLocal的厲害之處。Looper我們稱(chēng)之是消息循環(huán)器易遣,就是不斷的把消息從消息隊(duì)列中取出來(lái)彼妻,看一個(gè)創(chuàng)建Looper干了什么。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
主要是初始化了一個(gè)消息隊(duì)列豆茫,原來(lái)消息隊(duì)列是Looper里面的成員侨歉,記住了!@奖 为肮!,還保留了當(dāng)前線(xiàn)程肤京,有了mThread,我們就可以知道這個(gè)Looper是哪一個(gè)線(xiàn)程的Looper。Looper的成員非常少忘分,就幾個(gè)棋枕,看下面。
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
OK妒峦,在ActivityThread中的Looper.loop()這個(gè)死循環(huán)啟動(dòng)之前重斑,需要執(zhí)行 Looper.prepareMainLooper(),這個(gè)方法執(zhí)行以后肯骇,我們知道發(fā)生了以下幾件事情窥浪。
- 1、以餓漢式的方式創(chuàng)建了主線(xiàn)程的Looper對(duì)象
- 2笛丙、用sThreadLocal將主線(xiàn)程與這個(gè)Looper對(duì)象關(guān)聯(lián)起來(lái)
- 3漾脂、sThreadLocal.get一個(gè)Looper對(duì)象,賦值給sMainLooper胚鸯。
繼續(xù)看Looper.loop()里面骨稿,第二句關(guān)鍵代碼是final MessageQueue queue = me.mQueue;即獲取Looper中的消息隊(duì)列,之后是一個(gè)死循環(huán)姜钳,對(duì)消息隊(duì)列里面的消息進(jìn)行遍歷坦冠,在這里我們先留一個(gè)問(wèn)題 消息是怎么存到消息隊(duì)列里面去的?
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
在這個(gè)死循環(huán)中遍歷哥桥,通過(guò)queue.next()取出消息辙浑。
Message next() {
for (;;) {
//這句代碼水比較深,先跳過(guò)
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}
}
在同步synchronized中拟糕,這一大段代碼也就是寫(xiě)消息何時(shí)出隊(duì)列的事情判呕。
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
}
nextPollTimeoutMillis表示消息出隊(duì)列的時(shí)間,如果現(xiàn)在的時(shí)間now比Message要執(zhí)行的時(shí)間msg.when要小已卸,就減去現(xiàn)在的時(shí)間佛玄,計(jì)算一個(gè)新的時(shí)間給nextPollTimeoutMillis。如果消息的執(zhí)行時(shí)間已經(jīng)到了累澡,那么就取出這個(gè)消息返回并調(diào)用msg.markInUse()梦抢,把消息的狀態(tài)賦值為使用之中。
OK愧哟,在上面那個(gè)for循環(huán)中奥吩,消息是取到之后,就要進(jìn)行消息的分發(fā)了蕊梧,消息的分發(fā)也是有一套順序的霞赫。調(diào)用 msg.target.dispatchMessage(msg),進(jìn)行消息的分發(fā)肥矢,不知道target是什么的(是Handler對(duì)象端衰,標(biāo)識(shí)這個(gè)消息被誰(shuí)處理)叠洗,去看我的第一篇博客。
/**
* 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);
}
}
這里具體可以看我第一篇博客中****Message的處理順序****章節(jié)旅东,可以知道Message是怎么進(jìn)行分發(fā)的灭抑,從消息的分發(fā)可以看到,如果沒(méi)有Runnable的類(lèi)型的消息callback以及沒(méi)有Callback類(lèi)型的回調(diào)mCallback,那么就會(huì)回調(diào)Handler的handleMessge抵代。
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
dosomething();
}
};
上面試我們常常寫(xiě)的代碼腾节,走到這,相信你已經(jīng)知道我們常寫(xiě)的那個(gè)套路是怎么來(lái)的了荤牍。在Looper.looper中還有最后一句代碼 msg.recycleUnchecked();這個(gè)就不用講了案腺,主要做消息的回收操作,這里消息會(huì)進(jìn)入消息的全局池中康吵。
上面留下了一個(gè)問(wèn)題****消息是怎么存到消息隊(duì)列里面去的劈榨?****現(xiàn)在來(lái)分析分析,這個(gè)從我們發(fā)送消息(handler.sendMessage())來(lái)入手涎才,經(jīng)過(guò)查看源碼鞋既,sendMessage中會(huì)掉一系列方法,最終走到enqueueMessage中耍铜。如下圖邑闺。
對(duì)于enqueueMessage中代碼就不分析了,現(xiàn)在我們知道消息是怎么進(jìn)入消息隊(duì)列的棕兼,又是怎么被Looper給取走陡舅,交給Handler去處理的了,整個(gè)消息機(jī)制基本就弄清楚了伴挚。其實(shí)靶衍,嚴(yán)格來(lái)說(shuō),消息可以分為系統(tǒng)消息和我們自定義的消息茎芋,自定義的消息就是發(fā)送一個(gè)Message颅眶,然后在handlerMessage中進(jìn)行處理,那么系統(tǒng)的消息呢田弥,比如四大組件的生命周期回掉是系統(tǒng)消息涛酗,跨進(jìn)程通信也是系統(tǒng)消息,應(yīng)用程序退出還是一個(gè)系統(tǒng)消息偷厦。這些消息在哪里商叹?誰(shuí)來(lái)處理呢?在ActivityThread中有一個(gè)成員final H mH = new H();這個(gè)mH就是來(lái)處理系統(tǒng)消息的只泼。
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
//...
public static final int ENTER_ANIMATION_COMPLETE = 149;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
//...
case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
}
}
return Integer.toString(code);
}
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 PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&1) != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case HIDE_WINDOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
handleWindowVisibility((IBinder)msg.obj, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case DESTROY_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
msg.arg2, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
handleUnbindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
handleStopService((IBinder)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SUICIDE:
Process.killProcess(Process.myPid());
break;
//...
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
}
看到了吧剖笙,如果要退出應(yīng)用程序,需要發(fā)送一個(gè)SUICIDE消息请唱,綁定服務(wù)需要發(fā)送一個(gè)BIND_SERVICE消息等等弥咪。
最后總結(jié)一個(gè)Android消息機(jī)制涉及到的類(lèi)以及類(lèi)的重要方法过蹂,在整個(gè)機(jī)制中它們扮演著不同的角色也承擔(dān)著各自的不同責(zé)任。
Thread
負(fù)責(zé)業(yè)務(wù)邏輯的實(shí)施酪夷。
線(xiàn)程中的操作是由各自的業(yè)務(wù)邏輯所決定的榴啸,視具體情況進(jìn)行孽惰。Handler
負(fù)責(zé)發(fā)送消息和處理消息晚岭。
通常的做法是在主線(xiàn)程中建立Handler并利用它在子線(xiàn)程中向主線(xiàn)程發(fā)送消息,在主線(xiàn)程接收到消息后會(huì)對(duì)其進(jìn)行處理MessageQueue
負(fù)責(zé)保存消息勋功。
Handler發(fā)出的消息均會(huì)被保存到消息隊(duì)列MessageQueue中坦报,系統(tǒng)會(huì)根據(jù)Message距離觸發(fā)時(shí)間的長(zhǎng)短決定該消息在隊(duì)列中位置。在隊(duì)列中的消息會(huì)依次出隊(duì)得到相應(yīng)的處理狂鞋。Looper
負(fù)責(zé)輪詢(xún)消息隊(duì)列片择。
Looper使用其loop()方法一直輪詢(xún)消息隊(duì)列,并在消息出隊(duì)時(shí)將其派發(fā)至對(duì)應(yīng)的Handler.ThreadLocal
將線(xiàn)程和Looper相關(guān)聯(lián)
Please accept mybest wishes for your happiness and success