if (e.message != null && e.message!!.startsWith(“Unable to start activity”)) {
android.os.Process.killProcess(android.os.Process.myPid())
break
}
e.printStackTrace()
}
}
}
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
e.printStackTrace()
// TODO 异步线程崩溃,自行上报崩溃信息
}
}
}
通过上面的代码就可以就可以实现拦截UI线程的崩溃,耗时性能监控。但是也并不能够拦截所有的异常,如果在Activity的onCreate出现崩溃,导致Activity创建失败,那么就会显示黑屏。
ANR获取堆栈信息《Android:基于 Handler、Looper 实现 ANR 监控,获取堆栈》
源码剖析
通过上面简单的代码,我们就实现崩溃和ANR的拦截和监控,但是我们可能并不知道是为何实现的,包括我们知道出现了ANR,但是我们还需要进一步分析为何处出现ANR,如何解决。今天分析的问题有:
- 如何拦截全局崩溃,避免APP退出。
- 如何实现 ANR 监控。
- 利用 Handler 实现单线程池功能。
- Activity 的生命周期为什么用 Handler 发送执行。
- Handler 的延迟操作如何实现。
涉及的源码
/java/android/os/Handler.java
/java/android/os/MessageQueue.java
/java/android/os/Looper.java
/java/android.app/ActivityThread.java
复制代码
我们先从APP启动开始分析,APP的启动方法是在ActivityThread中,在main方法中创建了主线程的Looper,也就是当前进程创建。并且在main方法的最后调用了 Looper.loop()
,在这个方法中处理主线程的任务调度,一旦执行完这个方法就意味着APP被退出了,如果我们要避免APP被退出,就必须让APP持续执行Looper.loop()。
package android.app;
public final class ActivityThread extends ClientTransactionHandler {
…
public static void main(String[] args) {
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException(“Main thread loop unexpectedly exited”);
}
}
Looper.loop()
那我们进一步分析Looper.loop()
方法,在这个方法中写了一个循环,只有当 queue.next() == null
的时候才退出,看到这里我们心里可能会有一个疑问,如果没有主线程任务,是不是Looper.loop()
方法就退出了呢?实际上queue.next()
其实就是一个阻塞的方法,如果没有任务或没有主动退出,会一直在阻塞,一直等待主线程任务添加进来。
当队列有任务,就会打印信息 Dispatching to ...
,然后就调用 msg.target.dispatchMessage(msg);
执行任务,执行完毕就会打印信息 Finished to ...
,我们就可以通过打印的信息来