根据java线程的本质,当一个线程抛出异常时,在主线程中加try catch 是无法捕获到其抛出的异常的,如下面代码所示:
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickBtn(View view) {
try {
Thread thread = new Thread(new ExceptionThread());
ExecutorService service = Executors.newCachedThreadPool();
service.execute(thread);
} catch (Exception e) {
Log.d(TAG, "onClickBtn: catch the excepiton");
e.printStackTrace();
}
}
class ExceptionThread implements Runnable {
@Override
public void run() {
Log.d(TAG, "run: start to throw exception");
throw new RuntimeException();
}
}
点击按钮应用就会crash,异常log如下:
2018-11-12 16:32:08.106 32514-32545/com.air.testexceptioncatchinthead D/MainActivity: run: start to throw exception
--------- beginning of crash
2018-11-12 16:32:08.113 32514-32545/com.air.testexceptioncatchinthead E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
Process: com.air.testexceptioncatchinthead, PID: 32514
java.lang.RuntimeException
at com.air.testexceptioncatchinthead.MainActivity$ExceptionThread.run(MainActivity.java:37)
at java.lang.Thread.run(Thread.java:764)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
从上面实验中可以看到,在有多个线程时,另外一个线程是无法捕获到另外一个线程抛出的异常的。
那么这种异常如何捕获呢,java 在JDK5中引入了UncaughtExceptionHandler接口,实现如下:
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
Log.d(TAG, "uncaughtException: caught " + t + e.toString());
e.printStackTrace();
}
}
public void onClickBtn(View view) {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
new Thread(new ExceptionThread()).start();
}
此时点击,就会发现app已经不会crash了,完整代码如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickBtn(View view) {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
new Thread(new ExceptionThread()).start();
}
class ExceptionThread implements Runnable {
@Override
public void run() {
Log.d(TAG, "run: start to throw exception");
throw new NullPointerException();
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
Log.d(TAG, "uncaughtException: caught " + t + e.toString());
e.printStackTrace();
}
}
}
注意:JVM设计源于这样一种理念,线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。基于这样的理念,在java中线程方法的异常都应该在线程内部处理掉,这种外部捕获异常的方案通常情况下不应该使用