对于任何应用程序而言,线上崩溃都是不可避免的。毕竟完全依靠测试同学的测试,是无法测试出所有问题的。
所以收集线上应用崩溃的信息,并上传到服务器就显得格外重要了。
收集崩溃信息并上传的步骤:
1 收集崩溃信息并保存
2 应用崩溃后如何处理
3 下次启动发送崩溃信息
这里导致崩溃的异常为Java Exception,即UnChecked Exception。还有一个Native异常这里先不做讨论。
能够引起App Crash的为UnChecked Exception(即我们通常说的RunTime 异常),
理论上来说我们可以利用try cache将异常捕获。
但是我们不能将所有的代码全部try cache,而且除非我们特意抛出RunTime异常,否则当异常发生时,我们是不知道下一步逻辑该如何处理的。
如何收集?
当UnChecked异常发生时,系统会通知接口UncaughtExceptionHandler,回调uncaughtException()方法。
我们可以利用其回调的参数,收集异常的堆栈信息。
代码 1:
public static class UnhandledExceptionHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
public UnhandledExceptionHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
//收集异常信息
}
}
代码 2:
/**
* 收集异常信息
* @param throwable
*/
private static void getStackTraceInfo(Throwable throwable) {
Writer wr = new StringWriter();
PrintWriter pwr = new PrintWriter(wr);
throwable.printStackTrace(pwr);
//将崩溃堆栈信息保存到SharedPreferences中
SPHelper.getInstance().setString(SPConstant.LAST_ERROR_REPORT, wr.toString());
}
当异常发生时,会调用终止当前线程,并通知UncaughtExceptionHandler接口,如果没有显示设置handler,系统会通知默认的Handler.
我们要捕获当前线程的崩溃信息,需要设置为当前线程设置handler。
即调用接口:
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
我们可以看一下这个接口的说明:
Set the default handler invoked when a thread abruptly terminates due to an uncaught exception,
and no other handler has been defined for that thread.
即这个接口是针线程的。
一般我们会监控UI线程。所以我们可以在Application onCreate()方法中将其设置进去。
代码 3:
Thread.setDefaultUncaughtExceptionHandler(new UnhandledExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
那么我们为什么要传入defaultUncaughtExceptionHandler 的实例呢?
因为我们显示的设置了Handler,异常不会走Android的默认异常设置,这里传入defaultUncaughtExceptionHandler 是希望当我们收集完异常信息后,
依然希望调用Android默认的异常处理,即杀死进程,防止出现进程不可交互的状态。
这里便是我们之前说的第二布,崩溃之后的处理。崩溃之后收集好堆栈信息,依然走Android默认处理逻辑。
完整如下:
代码 4:
public class CrashReporter {
public static class UnhandledExceptionHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
public UnhandledExceptionHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
//收集崩溃信息
getStackTraceInfo(ex);
}finally {
//走Android默认的崩溃处理逻辑
uncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
}
/**
* 收集异常信息
* @param throwable
*/
private static void getStackTraceInfo(Throwable throwable) {
Writer wr = new StringWriter();
PrintWriter pwr = new PrintWriter(wr);
throwable.printStackTrace(pwr);
//将崩溃堆栈信息保存到SharedPreferences中
SPHelper.getInstance().setString(SPConstant.LAST_ERROR_REPORT, wr.toString());
}
public void report() {
//上传崩溃信息
}
最后在应用下次启动时,可以调用report()方法,上传崩溃信息。当然可能还需要同时上传一些手机型号,系统版本等相关信息。