Thread.setDefaultUncaughtExceptionHandler
Thread类还有另一个方法可以处理未捕获到的异常,即静态方法setDefaultUncaughtExceptionHandler()。
这个方法在应用程序中为所有的线程对象创建了一个异常处理器。
JVM的处理
当线程抛出一个未捕获到的异常时,JVM将为异常寻找以下三种可能的处理器。
1、线程对象的未捕获异常处理器
2、线程对象所在的线程组(ThreadGroup)的未捕获异常处理器
3、默认的未捕获异常处理器
最后,如果一个处理器都没有,JVM将堆栈异常记录打印到控制台,并退出程序。(这也是你经常看到的logcat崩溃打印,AndroidRuntime抛出的打印)
最简单的代码实现
sSystemUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread t, Throwable e) {
//write log to file;
sSystemUncaughtExceptionHandler.uncaughtException(thread, ex);
}
});
实战问题
增加下面两句测试代码,2秒在子线程制造NullPointer异常,6秒后在主线程制造NullPointer异常,
会出现如下现象:
第一次异常,正常处理,第二次主线程中的异常,一抛异常后,虚拟机立马退出,还没执行异常处理。
导致应用进程假死,界面冻结,应用无响应弹框
//在主线程中设置默认异常处理,仅写日志文件
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread t, Throwable e) {
//write log to file;
}
});
//启动后人为制造异常,第2秒一次,第6秒一次
{
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
String a = null;
Log.e(TAG, "make nullpointer exception in background thread");
Log.e(TAG, "len=" + a.length());
}
}).start();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
String a = null;
Log.e(TAG, "make nullpointer exception in main thread");
Log.e(TAG, "len=" + a.length());
}
}, 6 * 1000);
}