在Android系统内为什么会出现Crash?
简单来说,就是程序存在没有被try...catch的异常代码块,导致应用进程被强制销毁,系统Thread类内部有一个静态变量,它能监测到进程当前进程内,某个线程出现异常而没有被捕获的情况,然后对其进行善后处理:
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
下面来说说系统是怎么善后的?系统有一个RuntimeInit类 ,可以理解成所有进程的父类,这样每个进程初始化的时候,都是走其main()方法,如下:
在RuntimeInit.java类
public static final void main(String[] argv) {
......
commonInit();
......
}
里面主要有一个方法 commonInit()
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
/*
* set handlers; these apply to all threads in the VM. Apps can replace
* the default handler, but not the pre handler.
*/
LoggingHandler loggingHandler = new LoggingHandler();
Thread.setUncaughtExceptionPreHandler(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(newKillApplicationHandler(loggingHandler));
......
}
可以看到,方法里面主要是配置了两个Thread.UncaughtExceptionHandler对象,一个是LoggingHandler:这个是给Android Framework层使用,应用层无需关心,另外一个是KillApplicationHandler:这个是单独给应用层去善后事宜的,我们需要重点关注此类:
/**
* Handle application death from an uncaught exception. The framework
* catches these for the main threads, so this should only matter for
* threads created by applications. Before this method runs, the given
* instance of {@link LoggingHandler} should already have logged details
* (and if not it is run first).
*/
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
private final LoggingHandler mLoggingHandler;
public KillApplicationHandler(LoggingHandler loggingHandler) {
this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;
if (ActivityThread.currentActivityThread() != null) {
ActivityThread.currentActivityThread().stopProfiling();
}
// step1
// Bring up crash dialog, wait for it to be dismissed
ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
} catch (Throwable t2) {
if (t2 instanceof DeadObjectException) {
// System process is dead; ignore
} else {
try {
// step2
Clog_e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
// Even Clog_e() fails! Oh well.
}
}
} finally {
// step 3
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}
有没有很熟悉,第一步,弹出crash的对话框;第二步:crash日志输出;第三步,在finally 里面杀掉进程退出,我们在开发过程中是不是也经常遇到这样的情况?好了 我们回到我们主题上来,我们应用可以怎么巧妙的使用UncaughtExceptionHandler呢?
UncaughtExceptionHandler 使用技巧
1. 自定义UncaughtExceptionHandler
有时候,我们APP有这样的应用场景,比如某个线程出现未被成功捕获的异常,我们需要自定义全局捕获的UncaughtExceptionHandler,并且给一个交互更好的提示框或者文案,这时,需要我们自定义全局UncaughtExceptionHandler,那我们如何自定义呢?
在我们application主进程初始化时,在Thread中set自定义的UncaughtExceptionHandler对象:
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
设置完成之后,就可以替代系统的UncaughtExceptionHandler了,我们可以在自定义的对象里面做自己像做的事情:
private class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// do something
// 退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
2. 同时使用多个UncaughtExceptionHandler
第一点,只是告诉我们自定义UncaughtExceptionHandler,但是有时候,我们不需要覆盖掉系统的KillApplicationHandler,那怎么办呢?
其实可以这样:
private class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mUncaughHandler;
public MyUncaughtExceptionHandler(){
mUncaughHandler = Thread.getDefaultUncaughtExceptionHandler();
}
@Override
public void uncaughtException(Thread t, Throwable e) {
// do something
// 退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
// 系统的 UncaughtExceptionHandler
mUncaughHandler.uncaughtException(t,e);
}
}
先把系统UncaughtExceptionHandler存下来,放到最后在调用。