无论程序写的多完美, 发生crash都是无法避免的, 可能是机型适配, 也可能是你的代码写的不当。 当crash发生时, 系统会kill掉你的程序, 表现为闪退或者程序已停止运行, 这对用户来说是很不友好的, 当crash发生时,我们应该处理两件事,一是弹出一个通知友好的告知用户我们的程序出了问题要关闭,这样比闪退要温和一些,二是我们应该收集crash信息,在合适的时机上报后台服务器,在后续版本中修复这个bug。
要完成这个工作,核心是对java的Thread类有一定深度的理解。
在Thread.java源码中, 有一个静态变量defaultUncaughtHandler,被程序中所有的Thread共享。在程序中可调用Thread.setDefaultUncaughtExceptionHandler()来设置这个全局变量,从字面上理解就是设置系统默认的异常处理器。
/**
* Holds the default handler for uncaught exceptions, in case there is one.
*/
private static UncaughtExceptionHandler defaultUncaughtHandler;
/**
* Sets the default uncaught exception handler. This handler is invoked in
* case any Thread dies due to an unhandled exception.
*
* @param handler
* The handler to set or null.
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
Thread.defaultUncaughtHandler = handler;
}
实现步骤:
1. 实现自己的异常处理Handler
public class BrowserCrashHandler implements UncaughtExceptionHandler {
private static BrowserCrashHandler mInstance = null;
public static BrowserCrashHandler getInstance() {
if (null == mInstance) {
mInstance = new BrowserCrashHandler();
}
return mInstance;
}
public void init(Context ctx) {
//将当前实例设置为系统默认的异常处理器,这个异常处理器被所有的Thread共享.
Thread.setDefaultUncaughtExceptionHandler(this);
mContext = ctx;
}
//核心, 重写uncaughtException()方法,当程序有未被捕获的异常,系统会自动调用uncaughtException()方法。
//thread为未捕获异常发生所在的线程, ex为未捕获的异常实例。
@Override
public void uncaughtException(Thread thread, Throwable ex) {
//这里可以保存当前程序的状态,比如已经打开了哪些页面
//弹出通知告知用户程序即将关闭
//根据ex, 保存crash信息到sdcard
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
2. 初始化自定义的异常处理器
在Application的onCreate对它进行初始化, 因为在app的生命周期中,它是第一个被启动的, 早于任何的Activity, Service等.
public class BrowserApplicationContext extends Application {
@Override
public void onCreate() {
BrowserCrashHandler.getInstance().init(this);
}
效果:
模拟一个空指针异常
TextView tv = null;
tv.setVisibility(View.VISIBLE);
在自定义BrowserCrashHandler的uncaughtException()处打个断点, call stack如下.
crashHandler_1.png
crashHandler_2.png