Android全局异常捕获

Android全局异常的捕获

为了更好的完善我们的项目,通常需要对产品不停的迭代维护,计时的收集用户使用过程中发生的异常信息就显得非常重要。市面上有一些第三方工具提供该功能:例如:腾讯的Bugly、友盟统计等。
但是有时间为了减少我们的apk的大小或公司要求,会禁止使用这些第三方工具,所以我们需要自己提供这个简单的功能。

Thread.UncaughtExceptionHandler接口

当程序发生异常终止时,如果我们没有对其进行异常捕获处理,系统会调用该线程组的默认异常捕获处理器。我们想要对应用全局的异常进行捕获,实现思路就是自己写一个捕获器去替换系统默认的,然后对设备信息、版本信息、异常信息进行收集并上传到服务器进行分析。

Android 提供了这样一个接口Thread.UncaughtExceptionHandler

/**
     * Implemented by objects that want to handle cases where a thread is being
     * terminated by an uncaught exception. Upon such termination, the handler
     * is notified of the terminating thread and causal exception. If there is
     * no explicit handler set then the thread's group is the default handler.
     */
    public static interface UncaughtExceptionHandler {
        /**
         * The thread is being terminated by an uncaught exception. Further
         * exceptions thrown in this method are prevent the remainder of the
         * method from executing, but are otherwise ignored.
         *
         * @param thread the thread that has an uncaught exception
         * @param ex the exception that was thrown
         */
        void uncaughtException(Thread thread, Throwable ex);
    }

该接口就是系统异常终止时,用来处理异常的约束。

系统默认异常处理器:

Thread.getDefaultUncaughtExceptionHandler();

实现思路

  1. 自定义CrashHandler实现接口Thread.UncaughtExceptionHandler
  2. 在应用Application初始化时替换系统默认的异常处理器

自定义CrashHandler需要做的工作:

  1. 收集设备信息、版本信息、异常信息
  2. 写入本地记录
  3. 上传到服务器

实现示例

package com.zenkore.demowrite;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Process;
import android.text.TextUtils;

public class CrashHandler implements UncaughtExceptionHandler{


    private static CrashHandler INSTANCE = null;
    private CrashHandler(){

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

    private Context mContext;
    private UncaughtExceptionHandler mDefautHandler;

    public void init(Context context){
        mContext = context;
        mDefautHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }


    @Override
    public void uncaughtException(Thread thread, Throwable ex) {

        if (!handlerCrash(ex) && mDefautHandler != null) {
            // 没有处理还交给系统默认的处理器
            mDefautHandler.uncaughtException(thread, ex);
        }else{
            // 已经处理,结束进程
            Process.killProcess(Process.myPid());
            System.exit(1);
        }


    }
    /**
     * 自定义处理策略
     * @return true:已处理
     */
    private boolean handlerCrash(Throwable ex) {
        if (ex == null) {
            return false;
        }

        // 收集设备信息、版本信息、异常信息
        String info = collectDeviceInfo(mContext,ex);
        // 本地固化存储
        saveInfo(info);

        // 上传服务器(该功能可以独立到外边,定时上传或者进入应用时检测上传)

        return true;
    }

    /**
     * 收集设备信息
     * @param mContext2
     * @param ex 
     * @param infos
     */
    private String collectDeviceInfo(Context c, Throwable ex) {
        Map infos = new HashMap();
        // 收集版本信息
        try {
            PackageManager pm = c.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(c.getPackageName(), PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                String versionCode = pi.versionCode +"";
                String versionName = TextUtils.isEmpty(pi.versionName) ? "没有版本名称" : pi.versionName;
                infos.put("versionCode", versionCode);
                infos.put("versionName", versionName);
            }
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

        // 收集设备信息
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
            } catch (Exception e) {
            }
        }

        // 收集异常信息
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();

        // 转化为字符串
        StringBuffer sb = new StringBuffer();
        for (Map.Entry entry : infos.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key + "=" + value + "\n");
        }
        sb.append(result);

        return sb.toString();
    }


    /**
     * 保存异常信息到本地
     * @param infos
     */
    private void saveInfo(String infos) {
        // 把采集到的信息写入到本地文件
    }

}

使用示例

    CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(getApplicationContext());

你可能感兴趣的:(Android学习)