我们都知道主线程不能做太耗时的操作,否则容易发生ANR
,android
规定触发条件为:
1)KeyDispatchTimeout(5 seconds) --主要类型按键或触摸事件在特定时间内无响应
2)BroadcastTimeout(10 seconds)--BroadcastReceiver在特定时间内无法处理完成
3)ServiceTimeout(20 seconds)--小概率类型 Service在特定的时间内无法处理完成
估计有人就问了,既然主线程中耗时操作容易发生ANR
,那为何主线程中的Looper
存在死循环,为什么不会导致应用卡死,出现ANR
呢?
那么我们来一步一步将解答这一谜题
1、首先第一步,我们得找到Looper
创建的地方,这里不作详细描述,可以去搜索一下关于应用启动流程的文章,这里我先直接告诉大家是在ActivityThread
的Main
入口函数内,代码如下
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、我们进入Loop
的loop()
函数一探究竟,果然是有个for死循环。我们可以看到死循环里面主要是遍历MessageQueue
,若有消息则调用 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、接下来我们看看msg.target.dispatchMessage(msg)
方法是做了些什么骚操作?首先我们得知道msg.target
是啥,我们找到如下代码,可以大概知道这个target
实际上就是Message
所关联的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)
方法实际上调用的就是handler.dispatchMessage(msg)
咯,进进入Handler
类源码我们可以看到dispatchMessage
实际上就是执行了我们平常所回调的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
方法中,我们所设置的handler
为getHandler()
方法中返回的H
类,我们可以看到大量熟悉的消息处理,比如activity
的启动、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;
}
看到这里,你应该明白了吧?
实际上Loop
死循环的目的就在于
1、保持主线程处于一直运行状态
2、通过loop
循环遍历MessageQueue
,然后通过H handler
类的handleMessage
方法去处理activity
相关的start、pause、stop、destroy
等各类事件
这样看来,这个loop
死循环的设计非常合情合理,了解了这个机制后,你就不会疑惑为何Looper
死循环不会导致应用卡死了吧?
另外,我们也从这个问题知道,loop
死循环和ANR
是两码回事,ANR
是为了避免主线程做过长时间的耗时操作,导致应用卡顿体验差所做的一个限定,超出此限定,那么系统就要发飙了...哈哈,以此限制我们开发过程中,尽量避免在主线程中做耗时操作,而是将耗时操作放到子线程中去