安卓应用层Android 开发技术分享安卓开发博客

Android运行时异常处理(防crash)

2019-04-15  本文已影响168人  ccDown

什么,软件又崩溃了。。。。。。。
在这个时候总是很气愤,作为一个软件为什么你不能自己处理bug。那我们能不能让崩溃的地方可控也就是防止软件crash,就显得水平不那么菜了。。。hiahiahia。那就来吧。

要做到防crash首先要捕获系统抛出的不能处理的异常,把异常像JavaIO抛出的IO异常一样自己消化掉,然后让Looper继续looper()拿到接下来的message,整个Handler机制又开始转起来了。。。也就是成为了一个不会crash的软件了

(什么,这就完了?这不就是把线程的异常都捕获了集中处理么。。。)


第一步 :捕获异常

1.自定义一个Thread.UncaughtExceptionHandler类
2.调用Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)方法,使异常信息回调到自定义的uncaughtException中;
3.在自定义的uncaughtException方法中处理异常,如上传日志、保存为文件等。

1.自定义Thread.UncaughtExceptionHandler类

class CrashHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, final Throwable e) {
  }
}

2.设置异常处理

public void initHandler(final UncaughtExceptionCallBack uncaughtExceptionCallBack) {
    Thread.setDefaultUncaughtExceptionHandler(this);
}

3.异常回调处理信息

@Override
public void uncaughtException(Thread t, final Throwable e) {
    Log.e("CrashHandler  ", "偶吼吼,抓到错误信息了" + t.getName() + e.toString());
}

4.在Application的onCreate方法中调用initHandler方法就OK了


第二步:上边完成了基本的运行时异常回调处理,下面进行如何防止应用因为运行时异常崩溃

GitHub上大佬的思路是将Looper进行异常捕获,然后进行异常分发,把这个异常消费掉以后接着从MessageQueue中取下一个Message进行处理,那我们的过程就有了。

1.捕获异常
2.回调出去并进行相应的处理

代码实现思路:创建一个自定义的Thread.UncaughtExceptionHandler类,在Application中进行初始化事件的分发。

1.创建类

class CrashHandler implements Thread.UncaughtExceptionHandler{

/**自定义的异常处理回调*/
private UncaughtExceptionCallBack uncaughtExceptionCallBack;

public interface UncaughtExceptionCallBack{
    void caughtUncaughtException(Thread t,Throwable e);
}

private static CrashHandler crashHandler;

public static synchronized CrashHandler getInstance(){
    if (crashHandler == null){
        synchronized (CrashHandler.class){
            if (crashHandler == null) {
                crashHandler = new CrashHandler();
            }
        }
    }
    return crashHandler;
}

/**
 * 设置自定义的运行时异常处理
 * @param uncaughtExceptionCallBack
 */
public void initHandler(final UncaughtExceptionCallBack uncaughtExceptionCallBack){
    this.uncaughtExceptionCallBack = uncaughtExceptionCallBack;

    Thread.setDefaultUncaughtExceptionHandler(this);
     /**
     * 为什么要通过new Handler.post方式而不是直接在主线程中任意位置执行 
     * while (true) { 
     *      try { 
     *          Looper.loop(); 
     *      } catch (Throwable e) {
     *      } 
     *  }
     *
     * 这是因为该方法是个死循环,若在主线程中,比如在Activity的onCreate中执行时
     * 会导致while后面的代码得不到执行,activity的生命周期也就不能完整执行,
     * 通过Handler.post方式可以保证不影响该条消息中后面的逻辑。
     *
     * 摘抄自:https://github.com/android-notes/Cockroach/blob/master/%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90.md
     */
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    Looper.loop();
                } catch (Throwable e) {
                    if (uncaughtExceptionCallBack != null) {
                        uncaughtExceptionCallBack.caughtUncaughtException(Looper.getMainLooper().getThread(), e);
                    }
                }
            }
        }
    });
}

@Override
public void uncaughtException(Thread t, final Throwable e) {
    if (uncaughtExceptionCallBack != null) {
        uncaughtExceptionCallBack.caughtUncaughtException(Looper.getMainLooper().getThread(), e);
    }
}
}

2.Application中初始化事件

public class MyApplication extends Application {
@Override
public void onCreate() {
    super.onCreate();

    CrashHandler.getInstance().initHandler(new CrashHandler.UncaughtExceptionCallBack() {
        @Override
        public void caughtUncaughtException(Thread t, Throwable e) {
            Log.e("CrashHandler  ","偶吼吼,抓到错误信息了"+t.getName()+e.toString());
        }
    });
}
}

就酱,我们的软件长大一点点了,可以自己跟系统抢异常了。。。(还是增长自己的代码姿势才是王道)
整个流程仿照的GitHub一个封装好的Cockroach框架1.0版本,仰望大佬,大佬链接奉上:https://github.com/android-notes/Cockroach

上一篇下一篇

猜你喜欢

热点阅读