先来列举一下一般出现ANR的情况:
1.键盘输入事件、触摸无响应5s;
2.Receiver广播接收器10s超时无响应;
3.Service服务20s超时无响应;
...
再简单介绍一下
Handler会在应用启动之后,在ActivityThread的main 方法中启动:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
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");
}
这里我们可以看到三个关键行:
Looper.prepareMainLooper();
...
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop(); //循环
而Looper中loop方法会从MessageQueue中next方法中取出message
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;
}
...
msg.recycleUnchecked();
}
}
Message msg = queue.next(); // might block
而next方法会调用native方法 nativePollOnce,
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
...
}
}
当MessageQueue中没有消息时,queue.next()会阻塞在nativePollOnce()方法中,当nativePollOnce()被阻塞时,主线程会释放CPU资源,进入休眠状态。
直到获取到新的Message,就会唤醒主线程继续工作。
这里主线程进入休眠状态和死循环是有区别的:
休眠状态是指在内核状态里,主线程被挂起,线程状态转移到休眠状态。
死循环是指卡死是在主线程中执行一个耗时的操作,loop()会一直在处理一个消息,而for循环中有很多消息需要被处理,而这一个消息要处理很久,这一个消息的处理时间,会转变成其他的点击事件没有响应,从而触发ANR。