我們都知道主線(xiàn)程不能做太耗時(shí)的操作,否則容易發(fā)生ANR
连躏,android
規(guī)定觸發(fā)條件為:
1)KeyDispatchTimeout(5 seconds) --主要類(lèi)型按鍵或觸摸事件在特定時(shí)間內(nèi)無(wú)響應(yīng)
2)BroadcastTimeout(10 seconds)--BroadcastReceiver在特定時(shí)間內(nèi)無(wú)法處理完成
3)ServiceTimeout(20 seconds)--小概率類(lèi)型 Service在特定的時(shí)間內(nèi)無(wú)法處理完成
估計(jì)有人就問(wèn)了,既然主線(xiàn)程中耗時(shí)操作容易發(fā)生ANR
抒蚜,那為何主線(xiàn)程中的Looper
存在死循環(huán)篷扩,為什么不會(huì)導(dǎo)致應(yīng)用卡死思灰,出現(xiàn)ANR
呢?
那么我們來(lái)一步一步將解答這一謎題
1儡循、首先第一步舶吗,我們得找到Looper
創(chuàng)建的地方,這里不作詳細(xì)描述择膝,可以去搜索一下關(guān)于應(yīng)用啟動(dòng)流程的文章誓琼,這里我先直接告訴大家是在ActivityThread
的Main
入口函數(shù)內(nèi),代碼如下
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2调榄、我們進(jìn)入Loop
的loop()
函數(shù)一探究竟踊赠,果然是有個(gè)for死循環(huán)。我們可以看到死循環(huán)里面主要是遍歷MessageQueue
,若有消息則調(diào)用 msg.target.dispatchMessage(msg)
,否則阻塞在queue.next()
方法處
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;
...
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);
}
...
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
}
3每庆、接下來(lái)我們看看msg.target.dispatchMessage(msg)
方法是做了些什么騷操作筐带?首先我們得知道msg.target
是啥,我們找到如下代碼,可以大概知道這個(gè)target
實(shí)際上就是Message
所關(guān)聯(lián)的handler
:
public final class Message implements Parcelable {
...
Handler target;
...
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
4缤灵、msg.target.dispatchMessage(msg)
方法實(shí)際上調(diào)用的就是handler.dispatchMessage(msg)
咯伦籍,進(jìn)進(jìn)入Handler
類(lèi)源碼我們可以看到dispatchMessage
實(shí)際上就是執(zhí)行了我們平常所回調(diào)的handlerMessage
方法
/**
* 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);
}
}
5、我們回到ActivityThread
中的main
方法中腮出,我們所設(shè)置的handler
為getHandler()
方法中返回的H
類(lèi)帖鸦,我們可以看到大量熟悉的消息處理,比如activity
的啟動(dòng)胚嘲、pause作儿、stop、resume
等消息處理
final H mH = new H();
...
final Handler getHandler() {
return mH;
}
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 static final int CONFIGURATION_CHANGED = 118;
...
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
public static final int ATTACH_AGENT = 155;
public static final int APPLICATION_INFO_CHANGED = 156;
public static final int ACTIVITY_MOVED_TO_DISPLAY = 157;
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, "LAUNCH_ACTIVITY");
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;
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
maybeSnapshot();
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;
}
看到這里馋劈,你應(yīng)該明白了吧攻锰?
實(shí)際上Loop
死循環(huán)的目的就在于
1晾嘶、保持主線(xiàn)程處于一直運(yùn)行狀態(tài)
2、通過(guò)loop
循環(huán)遍歷MessageQueue
,然后通過(guò)H handler
類(lèi)的handleMessage
方法去處理activity
相關(guān)的start娶吞、pause垒迂、stop、destroy
等各類(lèi)事件
這樣看來(lái)妒蛇,這個(gè)loop
死循環(huán)的設(shè)計(jì)非常合情合理机断,了解了這個(gè)機(jī)制后,你就不會(huì)疑惑為何Looper
死循環(huán)不會(huì)導(dǎo)致應(yīng)用卡死了吧绣夺?
另外吏奸,我們也從這個(gè)問(wèn)題知道,loop
死循環(huán)和ANR
是兩碼回事乐导,ANR
是為了避免主線(xiàn)程做過(guò)長(zhǎng)時(shí)間的耗時(shí)操作苦丁,導(dǎo)致應(yīng)用卡頓體驗(yàn)差所做的一個(gè)限定,超出此限定物臂,那么系統(tǒng)就要發(fā)飆了...哈哈旺拉,以此限制我們開(kāi)發(fā)過(guò)程中,盡量避免在主線(xiàn)程中做耗時(shí)操作棵磷,而是將耗時(shí)操作放到子線(xiàn)程中去