手写CrashHandler实现UncaughtExceptionHandler拦截android异常

手写CrashHandler实现UncaughtExceptionHandler拦截android异常

作者:码字员小D

有点复杂,虽然知道原理,但是并不好从哪开始写了。。。。。。

首先这是个需要在整个app运行状态中都需要存在的对象,所以需要在application里初始化这个类,并且这个类实例~~~慢着!发现这里代码有疑问,application中只在oncreate方法里面初始化

public class CrashApplication extends Application {@Overridepublic void onCreate() {super.onCreate();//CrashHandler crashHandler = CrashHandler.getInstance();CrashHandler crashHandler = new CrashHandler();crashHandler.init(getApplicationContext());}}

在application里面并没有持有这个UncaughtExceptionHandler的实例(CrashHandler实现了UncaughtExceptionHandler接口类);仅仅在这里做初始化的工作,可以让UncaughtExceptionHandler这个类从一开始就拦截app运行时候的任何uncaught异常。

写CrashHandler类可以用单例写,也可以直接new对象。其实个人觉得这里单例也没太必要,直接new一个对象,这个对象反正是要被set到Thread类里去的

/** * Sets the default uncaught exception handler. This handler is invoked in * case any Thread dies due to an unhandled exception. * * @param handler *The handler to set or null. */public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {Thread.defaultUncaughtHandler = handler;}

上面的Thread.defaultUncaughtHandler就是系统的一个静态的实例。现在明白了其实在外面用static维持一个单例对象也没多大必要的原因了吧,系统里为我们维持了一个单例对象。

好了用单例初始化CrashHandler和直接new的两种方法都写出来吧

/** 保证只有一个CrashHandler实例 */public CrashHandler() {}//CrashHandler实例private static CrashHandler INSTANCE = new CrashHandler();/** 获取CrashHandler实例 ,单例模式 */public static CrashHandler getInstance() {return INSTANCE;}

下面我们需要讨论的是如何实现拦截异常。其实在android系统中有异常就会报错,闪退,application not response ANR。我们要做的是要分担下系统为我们默认对异常处理的任务而已。系统默认处理异常不友好,半天不响应,返回键也没用,最后会弹出个窗来要用户自己决定是否结束或者等待。

看android里Thread的源代码可以看到,还有个

public class ThreadGroup implements Thread.UncaughtExceptionHandler{

实现了Thread里面UncaughtExceptionHandler的接口,这个类里有系统线程组。。。好了这系统代码也不太好看

//获取系统默认的UncaughtException处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

我们需要获取系统的默认的defaultUncaughtHandler。不过疑惑的是这个defaultUncaughtHandler是谁初始化或者设置过去的呢,在Thread类里没有初始化过程。应该是系统给初始化设置过去的,暂时没找到具体代码实现。。。有知道的教教我呗!

然后呢,我们需要把自己写的UncaughtException类设置到系统变量defaultUncaughtHandler中去。

//设置该CrashHandler为程序的默认处理器Thread.setDefaultUncaughtExceptionHandler(this);

Ok,这里其实有点乱了。理理,首先我们需要获取一个系统默认的异常处理对象defaultUncaughtHandler,然后我们要把系统默认的异常处理对象设置成我们自己写的一个实现UncaughtException接口的对象。为什么要这么做呢?

首先系统默认的异常处理对象defaultUncaughtHandler维持了一个系统的异常处理对象,获取到这个系统处理对象可以通过调用uncaughtException(thread, ex);方法实现系统默认的异常处理。

而我们自己要把自己写的一个实现UncaughtException接口的对象设置成系统默认的异常处理对象是为了让系统检测到未catch的异常是会调用我们自己实现的uncaughtException(thread, ex)方法。然后在此方法里面实现处理逻辑。

理理就知道了,我们需要在实现了UncaughtException接口的CrashHandler类的uncaughtException方法里面实现处理逻辑。并且完成了自己的处理逻辑之后要执行系统原理默认对未捕获异常的处理。

PS:为什么一定要自己处理完后让系统默认的异常处理对象再处理一遍呢,因为系统默认有对异常处理有默认的处理方案,比如runtimeexcption运行时异常,nullexception空指针异常怎么处理。其实都是卡死半天,然后弹窗让用户决定怎么处理,等待还是结束。这个弹窗的两个选项,用户选择了等待,说明这个卡死状态是正常了,也许是网络请求慢但是确实是逻辑没错导致的。用户选择了结束,说明了这个确实是异常要立马结束掉。选择结束也就是用户选择了系统默认的异常处理方式,即调用了类似的defaultUncaughtHandler.uncaughtException(thread, ex)方法处理。

/** * 当UncaughtException发生时会转入该函数来处理 */@Overridepublic void uncaughtException(Thread thread, Throwable ex) {if (!handleException(ex) && mDefaultHandler != null) {//如果用户没有处理则让系统默认的异常处理器来处理mDefaultHandler.uncaughtException(thread, ex);//mDefaultHandler.uncaughtException(null, ex);//android.os.Process.killProcess(android.os.Process.myPid());//System.exit(0);} else {try {Thread.sleep(3000);} catch (InterruptedException e) {Log.e(TAG, “error : “, e);}//退出程序android.os.Process.killProcess(android.os.Process.myPid());System.exit(0);}}

这里回调接口方法的handleException(ex)是我们对异常的自定义处理。先不考虑。 其实这里模拟了系统的默认异常处理方式,即当没有默认异常处理的时候,会线程睡眠3秒然后退出应用。等价于卡死三秒然后弹窗提醒用户选择。自己处理完对未捕获异常处理后交由系统默认异常处理对象处理,默认就退出应用了。但是呢,这里我发现如果是mDefaultHandler.uncaughtException(thread, ex);处理的话第一次是正常退出应用的,当第二次点击应用图标的时候并没有执行到我们自己处理异常方法里。第三次点击应用图标时候直接弹出我们的异常处理方式。这是为什么呢?我的观点是系统有缓存异常机制,任务一样的错误一样的处理方式,就不再会执行我们自己写的异常处理方式里了,直接退出。这是我的观点。求反驳批判。所以我让mDefaultHandler.uncaughtException(null, ex);中的一个参数都传null则系统不会缓存记录异常,因为是null的,没异常啊~我这算是在调戏系统么。所以每次都能正常执行我们的处理方法。 当然你也可以在系统处理异常方式里面写上我们自己的异常处理方式。但是如果最后不退出应用的话是会卡死的,,,,,,其实这里个人更推荐自己写android.os.Process.killProcess(android.os.Process.myPid());因为,如果传一个null给系统默认异常处理会报null指针异常的~~

有时我们选择改变,并非经过深思熟虑,

手写CrashHandler实现UncaughtExceptionHandler拦截android异常

相关文章:

你感兴趣的文章:

标签云: