美文网首页
Android 应用防崩溃技巧

Android 应用防崩溃技巧

作者: 风的微笑 | 来源:发表于2017-09-04 00:34 被阅读216次

    需求

    前一段时间由于同事的一个RecyclerView的错误使用方式,导致了线上的App有部分使用者出现了页面闪退的情况,RecyclerView的LinearLayout抛出了IndexOutOfBoundsException.具体细节就不提了,由于数据刷新时列表滚动调用onLayoutChilden时报出的.
    但是由于这件事情,萌生了一个想法,能不能前台页面报异常归报异常,但尽可能减少闪退不要闪退.

    构思

    用try catch包住所有的代码段肯定是可行的,但是这方法也太蠢了….于是开始在网上查找资料,发现在一个地方可以动动手脚做做文章,就是Looper.
    Android的系统运行机制里简化的来看,一个App程序可以认为是在一个进程中执行了了一段无限循环的Java代码,反复的在从消息队列里面取出消息并执行,也就是Looper,MessageQueue(MQ),Handler,消息队列我们动不了什么手脚,但是Looper和Handler就可以做做文章了
    Android系统中的那段在无限循环读取消息队列的代码,是在Looper.loop()方法中被调用的,而本身异常捕获可以try catch,而多线程的异常则通过Java Thread的setDefaultUncaughtExceptionHandler来捕获,思路就是酱紫了.

    实现

    创建了一个类GuardianAngel,其实定义了3个静态成员变量,分别是标识位guarded,用来保存原本handler的sUncaughtExceptionHandler和用来处理捕获到的异常的sExceptionHandler.核心方法如下

    public static void protect(ExceptionHandler exceptionHandler) {
    if (guarded) {
    return;
    }
    if (exceptionHandler != null) {
    sExceptionHandler = exceptionHandler;
    }
    sUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
    sExceptionHandler.onException(e);
    }
    });
    guarded = true;
    while (guarded) {
    try {
    Looper.getMainLooper().loop();
    } catch (Throwable e) {
    sExceptionHandler.onException(e);
    }
    }
    }
    

    非常简单粗暴,首先判断标志位以及判断传进来的Handler是不是空的(类里面有个默认的Log.e输出堆栈的实现),然后记录下原有的UncaughtExceptionHandler,放一个新的由我们自己的sExceptionHandler代理的Handler,然后将状态标志改变并写一个死循环,手动的调用MainLooper.loop()方法读取messagequeue;
    原本主线程的MainLooper执行到我们的这个方法里的时候会在while (guarded)里陷入死循环,但是由于我们手动调用着MainLooper.loop()方法,于是系统looper依然在按照原样子读消息队列,只是这次loop方法已经被我们try catch住了,Java异常都会被捕获不再导致闪退.Native Crash和ANR依然会导致程序退出.

    想终止这种就调用方法将guarded重新置为false,并且将原本的DefaultExceptionHandler重新set回去就好了,这段代码蛮简单的就不给出了.

    相关文章

      网友评论

          本文标题:Android 应用防崩溃技巧

          本文链接:https://www.haomeiwen.com/subject/mdjsjxtx.html