未捕获的异常去哪里了?
在Thread.java里面有这样一个方法:
/**
* Set the default handler invoked when a thread abruptly terminates
* due to an uncaught exception, and no other handler has been defined
* for that thread.
*
* <p>Uncaught exception handling is controlled first by the thread, then
* by the thread's {@link ThreadGroup} object and finally by the default
* uncaught exception handler. If the thread does not have an explicit
* uncaught exception handler set, and the thread's thread group
* (including parent thread groups) does not specialize its
* <tt>uncaughtException</tt> method, then the default handler's
* <tt>uncaughtException</tt> method will be invoked.
* <p>By setting the default uncaught exception handler, an application
* can change the way in which uncaught exceptions are handled (such as
* logging to a specific device, or file) for those threads that would
* already accept whatever "default" behavior the system
* provided.
*
* <p>Note that the default uncaught exception handler should not usually
* defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
* infinite recursion.
*
* @param eh the object to use as the default uncaught exception handler.
* If <tt>null</tt> then there is no default handler.
*
* @throws SecurityException if a security manager is present and it
* denies <tt>{@link RuntimePermission}
* ("setDefaultUncaughtExceptionHandler")</tt>
*
* @see #setUncaughtExceptionHandler
* @see #getUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
defaultUncaughtExceptionHandler = eh;
}
Uncaught exception handling is controlled first by the thread, then
* by the thread’s ThreadGroup object and finally by the default
* uncaught exception handler.
这里表明了“未捕获的异常”的处理顺序是:
1. 异常所在线程的uncaughtExceptionHandler,
2. 线程所在线程组
3. Thread中的静态defaultUncaughtExceptionHandler,
经过测试和分析,这里的处理顺序是指当上一级处理了,下一级将不再进行处理
我们继续分析这个传递顺序是怎么实现的
首先,我在Thread类中找到这个方法
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
这里已经明确说明了,这个方法是由JVM发起调用的。
这是异常处理发生的第一个地方
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
来到这里,我们就可以知道,当本线程的UncaughtExceptionHandler为空时,就交给线程组来处理。
我们看看线程组是怎么处理的:
首先它实现了异常处理接口
class ThreadGroup implements Thread.UncaughtExceptionHandler
线程组处理的过程:
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
//递归交给最顶端的线程组处理
parent.uncaughtException(t, e);
} else {
//获取全局的(未捕获)异常处理器
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
//由defaultUncaughtExceptionHandler处理
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
ThreadDead的描述:
An instance of {@code ThreadDeath} is thrown in the victim thread when the (deprecated) {@link Thread#stop()} method is invoked.
按照描述,ThreadDead已经不再使用了,所以当未设置Thread.defaultUncaughtExceptionHandle时,就打印异常栈
至于应用为什么会崩溃?暂时找不到相关代码
配置自己的未捕获异常处理器(奔溃处理)
经过测试,当设置了处理器之后,android应用遇到未捕获异常时会调用我们的uncaughtException方法,而不会崩溃
一般在MyApplication中配置,也可以在主活动中进行。
//默认未捕获异常处理器
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
Log.d("MainActivity", "崩溃处理");
Intent intent = new Intent(getContext(), ErrorActivity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
// Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("err", "应用遇到未处理的错误,即将关闭!\n出错线程:" + t.getName() + "\n出错信息:" + e.getLocalizedMessage());
startActivity(intent);
//这里必须killProcess,否则会黑屏
android.os.Process.killProcess(android.os.Process.myPid());
}
});
/**
* 奔溃跳到这里
*/
public class ErrorActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_error);
String err = getIntent().getStringExtra("err");
//弹框提示
new AlertDialog.Builder(this)
.setCancelable(false)
.setTitle("错误")
.setMessage(err)
.setPositiveButton("重启应用", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Util.getContext(), MainActivity.class);
startActivity(intent);
finish();
}
})
.show();
}
}