java 中的全局异常捕获机制

  • Post author:
  • Post category:java


我们讲这个全局异常捕获器UncaughtExceptionHandler之前,我们先来想个问题,先看下下面这段代码和一张图片

public class SecnodActivity extends BaseActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        String str = null;
        str.equals("ssdad");  //空指针异常,平常我们没有注意到的异常

        findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BaseActivity.getInstance().removeAll();
            }
        });
    }
}

效果

有异常,应用崩掉了是不是.但我们平常的手机应用你看过这样子的么..好像没有吧,我印象中没看过.那你觉得是它们写的程序没有bug么,这不可能吧.就算经过了严格的测试环节应该还是有那些很难发觉的bug吧.但为什么没有出现这种效果呢.这时候就归功于我们的全集异常捕获器UncaughtExceptionHandler了,应用崩掉会出现这个黑色的提示框是因为安卓系统给我们的应用设置了默认的全局异常捕获器,怎么证明呢,那我们就来改变全局异常捕获器,UncaughtExceptionHandler它是一个接口,我们创建一个类来实现它

public class CauchExceptionHandler implements Thread.UncaughtExceptionHandler{


    private static CauchExceptionHandler cauchExceptionHandler = null;

    private CauchExceptionHandler(){

    }

    public static CauchExceptionHandler getInstance(){

        if (cauchExceptionHandler == null){

            synchronized (CauchExceptionHandler.class){

                if (cauchExceptionHandler == null){
                    cauchExceptionHandler = new CauchExceptionHandler();
                }
            }
        }

        return  cauchExceptionHandler;
    }

    public void setDefaultUnCachExceptionHandler(){ //在Application开始时调用

       Thread.setDefaultUncaughtExceptionHandler(this); //设置应用默认的全局捕获异常器
    }

    @Override //应用没有捕抓的异常会到这里来,如果我们设置了应用的默认全局捕抓异常为CauchExceptionHandler的话
    public void uncaughtException(Thread thread, Throwable throwable) {

        Log.d("CauchExceptionHandler", throwable.getMessage()); //异常信息

        //可以上传错误日志

    }
}

继承它我们需要实现uncaughtException这个方法,当有未捕获的异常发生时,全局异常捕获器就会捕获它,然后调用这个方法.Thread.setDefaultUncaughtExceptionHandler(this)这是设置全局异常捕获器,我们在这里可以用来替换掉系统默认设置的捕获器,我们在应用开始的时候就设置它

public class MyAplication extends Application{

    @Override
    public void onCreate() {
        super.onCreate();
        //应用开始就设置全局捕获异常器没有设置就会用系统默认的
        CauchExceptionHandler.getInstance().setDefaultUnCachExceptionHandler();
    }
}

这样就可以了,来测试一下.

效果1

捕获的异常信息

07-09 11:50:40.554 10672-10672/? D/CauchExceptionHandler: Unable to start activity ComponentInfo{com.it.uncaughtexceptionhandle/com.it.uncaughtexceptionhandle.SecnodActivity}: java.lang.NullPointerException

因为异常捕获器捕获异常会调用uncaughtException,而我们在那里面只打印了日志,并没有做其它任何的处理,所以处于一种阻塞像死机了的状态,这里是不是证明了系统是给我们设置了默认的全局异常捕获器的,为了不让我们应用出异常了有这种阻塞像死机的情况,让我们有更好的体验,不像我们刚开始学C语言的时候,什么内存溢出然后exe程序直接来个像什么,反正很烦的那种…反正想剁了它..嗯,这里是android系统提示我们的应用出异常了,对于我们开发人员当然没事,但是对于用户会怎么想呢,会不会骂我们的应用垃圾什么的,所以我们这么处理

@Override //应用没有捕抓的异常会到这里来,如果我们设置了应用的默认全局捕抓异常为CauchExceptionHandler的话
    public void uncaughtException(Thread thread, Throwable throwable) {

        Log.d("CauchExceptionHandler", throwable.getMessage()); //异常信息

        //可以上传错误日志给服务器

        //一般的异常发布前都测试的出来吧,这种应该是很少出现的那种,所以直接关闭应用吧.用户也有点难能重现BUG吧
        BaseActivity.getInstance().removeAll();
        android.os.Process.killProcess(android.os.Process.myPid());
        //关闭虚拟机,释放所有内存
        System.exit(0);               //应用闪退像不像,我也不知道怎么重启应用,知道的告诉我

    }

效果2

这样子闪退的情况,好像我们也碰到过吧.应该大家大部分情况骂的是手机垃圾吧,O(∩_∩)O哈哈~