关于UncaughtExceptionHandler的研究

除去第三方的异常处理,一般APP都有自己的异常处理函数。

自定义自己的异常处理函数很有好处,可以增加自己额外的错误定位信息,也可以在三方处理以外进行自己的额外的操作。

网上例子很多,一般的异常处理无非是这样:

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

先执行自己的处理,根据处理结果和是否存在默认处理函数决定是否执行默认的处理,

如果处理好了直接退出程序。

然而实际当中我们往往集成了一些三方SDK,很多SDK都有自己的异常处理函数。

比如蒲公英,比如友盟。

项目中丧心病狂的同时用了两个。

最近需要把错误信息重新调整一下,就进行了一下研究。

在项目中,蒲公英的异常收集初始化是在自己的异常收集之前,也就是说,我自己异常处理函数里的mDefaultHandler,其实是蒲公英的,而蒲公英的则是系统的。


尝试了几种情况:

1.直接执行自己的操作并kill,功能正常。

2.直接执行default并kill,功能正常。

3.执行postDelay + kill,无法退出程序

4.执行new Thread + kill,功能正常

6.Toast必须new Thread + Looper初始化才能显示

7.用Log4j在处理函数里用同步方式直接写日志后kill,可以写如成功

8.使用new Thread + default 执行kill,无法退出

9.使用new Thread + kill,可以退出

10.使用new Thread + (default + kill 顺序执行),无法退出

11.不初始化蒲公英异常处理直接new Thread + default,可以退出


追踪蒲公英的异常处理代码,如下:

    public void uncaughtException(Thread thread, Throwable exception) {
        if(com.pgyersdk.conf.a.a == null) {
            this.c.uncaughtException(thread, exception);
        } else {
            (new com.pgyersdk.crash.b(this, exception)).start();
            if(!this.a) {
                this.c.uncaughtException(thread, exception);
            } else {
                Process.killProcess(Process.myPid());
                System.exit(10);
            }
        }
    }
无非是多了两个判断,但是其中似乎多了一段Thread中执行的代码,其中执行了什么?看不到。

问了蒲公英的技术支持,说是有冲突。必须直接调用他们的异常处理函数。

所以无奈,本想在自己的处理中搞个延时,弹个Toast啥的,现在看来,有点复杂。

看来在接入多个带异常处理的三方SDK时,为了安全起见,如果自定义异常处理,还是不要在线程中调用他们的处理函数,以防冲突。


上面还得出的结论有:

Handler不好使

Toast必须初始化Looper


最后,异常处理的代码变成了这个样子,其实和文章开头的差不多,脸红:

public class XCrashHandler implements Thread.UncaughtExceptionHandler {

    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private Context mContext;

    public XCrashHandler(){
    }

    public void register(Context context){
        this.mContext = context.getApplicationContext();
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(final Thread thread, final Throwable ex) {
        final CharSequence str = getLastWord(ex);
        XLog.e(XLog.BASE, str.toString());
        if (mDefaultHandler != null){
            mDefaultHandler.uncaughtException(thread, ex);
        }else{
            exit();
        }
    }

    private void showToast(final Context context, final String msg) {
        threadDelay(new Runnable() {

            @Override
            public void run() {
                Looper.prepare();
                ToastUtil.longToast(context, msg);
                Looper.loop();
            }
        }, 0);
    }

    private void exit(){
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(0);
    }

    @Deprecated
    private void postDelay(final Runnable runnable, final int delay){
        new Handler().postDelayed(runnable, delay);
    }

    private void threadDelay(final Runnable runnable, final int delay){
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException e) {
                    XLog.e(XLog.BASE, "error : "+ e);
                }
                runnable.run();
            }
        }).start();
    }

    private CharSequence getLastWord(Throwable e){
        StringBuffer sb = new StringBuffer();
        final String sep = "\n";
        sb.append(sep + "-------------------- LAST WORD --------------------" + sep);
        sb.append(new Date() + sep);
        sb.append(BuildInfoHelper.build());
//        sb.append("" + e.toString() + sep);
//        StackTraceElement [] stackTrace = e.getStackTrace();
//        for (int i = 0; i < stackTrace.length; i++) {
//            sb.append("    at " + stackTrace[i].getClassName()
//                    + "." + stackTrace[i].getMethodName() + "(" + stackTrace[i].getFileName()
//                    + ":"  + stackTrace[i].getLineNumber() + ")"
//                    + sep);
//        }
        sb.append(getErrorInfoFromException(e));
        return sb;
    }

    public static String getErrorInfoFromException(Throwable e) {
        final String sep = "\n";
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            return sep + sw.toString() + sep;
        } catch (Exception e2) {
            return "bad getErrorInfoFromException";
        }
    }

    private static class BuildInfoHelper{

        private static final String fmt = "%15s %s\n";
        private static StringBuffer sb;

        public static StringBuffer build(){
            sb = new StringBuffer();
            append("SDK_INT", Build.VERSION.SDK_INT);
            append("CODENAME", Build.VERSION.CODENAME);
            append("INCREMENTAL", Build.VERSION.INCREMENTAL);
            append("RELEASE", Build.VERSION.RELEASE);
            append("BOARD", Build.BOARD);
            append("BOOTLOADER", Build.BOOTLOADER);
            append("BRAND", Build.BRAND);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                append("SUPPORTED_ABIS", Build.SUPPORTED_ABIS);
            }else{
                append("CPU_ABI", Build.CPU_ABI);
                append("CPU_ABI2", Build.CPU_ABI2);
            }
            append("DEVICE", Build.DEVICE);
            append("DISPLAY", Build.DISPLAY);
            append("FINGERPRINT", Build.FINGERPRINT);
            append("HARDWARE", Build.HARDWARE);
            append("HOST", Build.HOST);
            append("ID", Build.ID);
            append("MANUFACTURER", Build.MANUFACTURER);
            append("MODEL", Build.MODEL);
            append("PRODUCT", Build.PRODUCT);
            append("SERIAL", Build.SERIAL);
            append("TAGS", Build.TAGS);
            append("TYPE", Build.TYPE);
            append("USER", Build.USER);
            append("TIME", Build.TIME);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                append("RADIO_VERSION", Build.getRadioVersion());
            }
            return sb;
        }

        private static void append(Object ... arg){
            sb.append(String.format(fmt, arg));
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值