作为开发同学,每天都在面临各种各种的崩溃问题。
我们都如果在Android应用中发生了未捕获的崩溃问题,不管是在主线程还是在子线程,应用都会直接退出。
但是Java程序,子线程抛出的异常,不会引起程序的退出。
那你们知道JVM是如何处理应用未捕获崩溃的吗?Android又是怎样在发生崩溃时让程序退出的呢?
崩溃处理机制
当一个线程抛出异常时,JVM会调用线程的dispatchUncaughtException
方法,所有未被捕获的异常,最后都会交给UncaughtExceptionHandler处理。
对于一个线程来说,UncaughtExceptionHandler
有多个,首先有针对单个线程的unCaughtExceptionHandler
,然后还有静态的首先有一个静态的defaultUncaughtExceptionHandler
和defaultUncaughtPreExceptionHandler
,这个是对每个线程都生效的。
处理顺序:未捕获的异常,先由线程处理,然后由线程的ThreadGroup
处理,最后再由默认异常处理程序处理。
Android发生崩溃后
为什么Android发生异常后,不管是在主线程还是在子线程,都会引起程序crash退出呢?
其实是因为Android给所有线程都设置了一个defaultExceptionHandler
,这个ExceptionHandler
的处理逻辑就是让程序退出。
下面我们来看源码。
在应用程序被创建的时候,RuntimeInit
会设置一个默认的异常处理Handler
,这个异常处理Handler
就是KillApplicationHandler
。从名字就可以看出,这个Handler
主要负责杀掉App进程。
// RuntimInit
protected static final void commonInit() {
LoggingHandler loggingHandler = new LoggingHandler();
// 设置preExceptionHandler
Thread.setUncaughtExceptionPreHandler(loggingHandler);
// KillApplicationHandler 作为全局 Handler
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
//...
}
KillApplicationHandler
会先调用loggingHandler
打印日志,然后杀掉当前进程。
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
private final LoggingHandler mLoggingHandler;
public KillApplicationHandler(LoggingHandler loggingHandler) {
// 传入loggingHandler用于打日志
this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
// 打日志
ensureLogging(t, e);
// 已经在crash中了,不处理了
if (mCrashing) return;
mCrashing = true;
// ...
} catch (Throwable t2) {
// ...
} finally {
// 通知内核杀掉进程
Process.killProcess(Process.myPid());
// 停止VM
System.exit(10);
}
}
所以,当出现未捕获的异常时,会交给KillApplicationHandler
中的uncaughtException
,从而直接让程序退出。与此同时,我们也可以从adb日志中看到崩溃的具体堆栈。
下一篇,我们讲讲如何借用 uncaughtExceptionHandler
的原理来实现Android应用永不崩溃。