CrashHandler未捕获类型异常处理

当用户在使用app出现崩溃现象时,我们需要知道是什么原因,并将原因记录下来上到服务器,这样以后我们就可以知道具体是什么原因了

  一般而言,我们在开发的时候为了避免出现bug,在一些疑似有可能出现bug的地方会主动加上try{ } catch( ) { },当然有些时候编译器的检测机制也会提示我们需要加try catch比如JSONObject取值的时候就会让做空指针异常处理。
  不过不管做多少预处理,但是!!!bug总会在你意想不到的时候突然降临-。-

CrashHandler未捕获类型异常处理_第1张图片
没有一点点防备,也没有一丝顾虑,你就这样出现在我的世界里,带给我惊喜,情不自已

  如果是在开发阶段的话还不是一个多大的问题,插上USB调试看下log就行 虽然并不一定能够稳定复现
but!!!项目上线出了bug,先不说用户体验不好,单开发者自己而言也是很悲催的一件事。单凭热心用户  乱七八糟,莫名其妙 的三言两语基本弄不明白是哪里的问题。
所以,这时候我们就需要一种方法,让我们知道用户app崩溃的原因。
这也就是这篇文章罗里吧嗦这么久要讲的 囧oz


和以前一样,先贴代码

public class CrashHandler implements UncaughtExceptionHandler {

    private static CrashHandler instance = null;
    private CrashHandlerListener crashHandlerListener = null;
    private UncaughtExceptionHandler defaultUncaughtExceptionHandler = null;

    private CrashHandler(){ }
    public static CrashHandler getInstance() {
        if (instance == null)
            instance = new CrashHandler();
        return instance;
    }

    public void init() {
        //  获取系统默认的为捕获异常处理器
        this.defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        //  设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    public void init(CrashHandlerListener listener) {
        init();
        this.crashHandlerListener = listener;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        writeExceptionToSDCard(throwable);
        uploadedExceptionToServer(throwable);
        //  如果系统存在默认的未捕获异常处理器则让系统处理,否则自己处理
        if (defaultUncaughtExceptionHandler != null) {
            defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Looper.prepare();
                    if (crashHandlerListener != null) {
                        crashHandlerListener.uncaughtException();
                    } else {
                        ToastUtil.showShort("很抱歉,程序出现异常,即将退出.");
                        new Handler().postDelayed(new Runnable(){
                            public void run() {
                                App.getInstance().exit();
                            }
                        }, 2000);
                    }
                    Looper.loop();
                }
            }).start();
        }
    }

    /**
     * 将异常信息写入SD卡
     * @param throwable 未捕获异常
     */
    private void writeExceptionToSDCard(Throwable throwable) {
        // TODO: 2017/8/4 将异常信息写入SD卡
        Log.i("###########", throwable.toString());
    }

    /**
     * 将异常信息上传到服务器
     * @param throwable 未捕获异常
     */
    private void uploadedExceptionToServer(Throwable throwable) {
        // TODO: 2017/8/4 将异常信息上传到服务器
    }

    public interface CrashHandlerListener {
        void uncaughtException();
    }

}

单例

  其实没有必要使用单例模式,我这边使用单例仅是强迫症。。。因为CrashHandler是需要在整个App运行状态中去捕获全局所有异常的,因此一般都是在Application中去初始化,然后初始化之后也没有其他什么操作了,毕竟目的是捕获异常。所以总体而言,CrashHandler只在Application中被调用了一次,单例不单例也就没什么影响了。

UncaughtExceptionHandler

un(没有)caught(接住)exception(异常)handler(处理)

    @FunctionalInterface
    public interface UncaughtExceptionHandler {
        void uncaughtException(Thread var1, Throwable var2);
    }

android本身是提供有未捕获异常处理机制的,所以这就省了很多事了,我们只需要考虑拦截实现。
在刚刚的代码中,可以看到两句看起来略有冲突的语句:

this.defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);

第一句Thread.getDefaultUncaughtExceptionHandler()是获取系统默认的处理器
第二句Thread.setDefaultUncaughtExceptionHandler(this)是把我们实现的UncaughtExceptionHandler接口CrashHandler设置为系统默认的处理器
So,理一下,我们先获取了一个系统默认的处理器,然后把我们自己实现的接口设置为默认的。
首先Thread.getDefaultUncaughtExceptionHandler()维护了一个异常处理器,把这个对象赋值给defaultUncaughtExceptionHandler,这样当我们想通过系统默认处理器的时候就可以通过defaultUncaughtExceptionHandler去调用了;
然后Thread.setDefaultUncaughtExceptionHandler(this)这个方法是为了当系统检测到未捕获异常时会使用我们实现的接口
其实说起来有点啰嗦,想想a、b变量交互的逻辑应该就能清楚很多
说完这些,我们也发现了重点就是我们实现的接口uncaughtException(thread, throwable)

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        writeExceptionToSDCard(throwable);  //  写入SD卡
        uploadedExceptionToServer(throwable);  //  上传到服务器
        //  如果系统存在默认的未捕获异常处理器则让系统处理,否则自己处理
        if (defaultUncaughtExceptionHandler != null) {
            defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
        } else {
            // TODO: 2017/8/7 自己的处理
        }
    }

你可能感兴趣的:(CrashHandler未捕获类型异常处理)