Android之利用Thread.setDefaultUncaughtExceptionHandler实现崩溃监测

      我们经常会面临这样的情景:应用发布上线后,收到用户反馈说app崩溃了,但自己重现不了。这时候怎么办呢?

很多朋友都会想到用友盟等第三方插件实现,但鉴于安全性要求较高的支付系统,是不允许使用未知来源压缩包/有后门的第三方插件。这时候我们可以考虑自己写一个。

先来看一段代码,了解UncaughtExceptionHandler的最基本用法:

/**
 * 程序入口
 */
public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {
                Toast.makeText(App.this, "程序遇到错误:" + ex.getMessage(), Toast.LENGTH_LONG).show();
                ex.printStackTrace();
            }
        });
    }
}


Java中有两种异常:已检测异常(Checked exceptions)和未检测异常(Unchecked exceptions)
前者必须使用 throws 或 try catch 进行异常处理;后者不需要指定或捕获。
因为run()方法不接受throws语句,所以当一个检测的异常在一个Thread对象的run()方法中抛出,我们需要对其进行捕获并做相应的处理。

java对未检测异常默认处理方式是:将堆栈跟踪信息写到 控制台中(或者记录到错误日志文件中)然后退出程序。常见的APP崩溃现象(应用程序XXX已经停止),正是基于这一原理。

我们可以通过UncaughtExceptionHandler,用来捕获并处理在一个线程对象中抛出的未检测异常,以避免程序终止。。


通俗的理解:setDefaultUncaughtExceptionHandler 相当于app全局的 catch ,用于捕获程序未捕获的异常。


基本逻辑的实现:

public class CrashManager implements UncaughtExceptionHandler {
    public static final String TAG = "CrashHandler";
    // CrashHandler实例
    private static CrashManager instance;
    // 程序的Context对象
    private Application application;
    // 系统默认的UncaughtException处理类
    private UncaughtExceptionHandler mDefaultHandler;

    /**
     * 保证只有一个CrashHandler实例
     */
    private CrashManager(Context context) {
        application = (Application) context.getApplicationContext();
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 获取CrashHandler实例 ,单例模式
     */
    public static CrashManager getInstance(Context context) {
        CrashManager inst = instance;
        if (inst == null) {
            synchronized (CrashManager.class) {
                inst = instance;
                if (inst == null) {
                    inst = new CrashManager(context.getApplicationContext());
                    instance = inst;
                }
            }
        }
        return inst;
    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        TaskManager.getInstance(application).saveErrorLog(ex);
        mDefaultHandler.uncaughtException(thread, ex);
    }

}



日志写入sdcard代码:

public class SaveErrorTask extends Task {
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.CHINA);
    private Context context;
    private Throwable ex;

    public SaveErrorTask(Context context, Throwable ex) {
        setPriority(TaskPriority.UI_LOW);
        this.context = context;
        this.ex = ex;
    }

    @Override
    protected Void doInBackground(Object... arg0) {
        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();
        String time = formatter.format(new Date());
        String fileName = time + ".txt";
        StringBuilder stringBuffer = new StringBuilder();
        DeviceInfo deviceInfo = Utils.getDeviceInfo(context);
        stringBuffer.append("\nsdkVersion:" + deviceInfo.sdkVersion);
        stringBuffer.append("\nmanufacturer:" + deviceInfo.manufacturer);
        stringBuffer.append("\nmodel:" + deviceInfo.model);
        stringBuffer.append("\nversion" + ConfigManager.getVersionName(context));
        stringBuffer.append("\nerrorStr:" + result);
        stringBuffer.append("\ntime:" + time);
        String filePath = CacheFileUtils.getLogPath(fileName);
        CacheFileUtils.saveErrorStr(filePath, stringBuffer.toString());
        return null;
    }
}


初始化:

public class MyApplication extends MultiDexApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化 错误日子系统
        CrashManager.getInstance(this);
       
    }
}


参考链接:

http://www.importnew.com/14434.html

https://www.cnblogs.com/whoislcj/p/5468190.html





你可能感兴趣的:(Android)