为什么需要这个工具
在产品测试的时候,如果能在出现程序异常导致崩溃的情况下记录当时的现场,那么开发人员就能能够快速地定位到问题所在
这个工具能够提供什么功能
- 保存异常日志到 "手机存储/程序包名/crash/" 文件夹下
- 记录异常发生的时间、原因
- 每小时内产生的日志都记录在一个文件中
原理
如果线程因为一个无法捕获的异常而终止,可以使用一个实现了接口 Thread.UncaughtExceptionHandler
的类来进行着手处理。
在异常发生的时候,异常的有关信息会作为参数传入 Thread.UncaughtExceptionHandler 的 public void uncaughtException(Thread t, Throwable ex)
方法中去。我们只需要在这个方法中捕获异常日志,把日志保存到文件或者显示到界面上。
实现
新建一个类 CrashCanary,实现 Thread.UncaughtExceptionHandler 接口的方法
public class CrashCanary implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable ex) {
}
}
在这三个方法中,要做的事情有
- 获取异常日志
- 格式化异常日志
- 保存异常日志到本地文件
- 退出崩溃的App
获取异常日志
private String getCrashLogContent(Throwable ex) {
Writer strWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(strWriter);
ex.printStackTrace(printWriter);
Throwable nextCause = ex.getCause();
while (nextCause != null) {
nextCause.printStackTrace(printWriter);
nextCause = nextCause.getCause();
}
String crashLogContent = strWriter.toString();
printWriter.close();
return crashLogContent;
}
格式化异常日志
将时间加上
private String formatCrashLog(String crashLogContent, long timeMillis) {
return TextUtils.concat(
">>>>>>>>>>>>>> ", DateFormat.format(LOG_RECORD_TIME_FORMAT, timeMillis), ">>>>>>>>>>>>>> ",
"\r\n",
crashLogContent,
"\r\n",
"\r\n"
).toString();
}
保存异常日志到本地文件
public static void writeToFile(String dir, String fileName, String content, String encoder) {
File file = new File(dir, fileName);
File parentFile = file.getParentFile();
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
if (!parentFile.exists()) {
parentFile.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
osw = new OutputStreamWriter(new FileOutputStream(file, true), encoder);
bw = new BufferedWriter(osw);
bw.append(content);
bw.append("\r\n");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSilently(bw);
closeSilently(osw);
}
}
退出崩溃的App
private void exitApp() {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
总结
原理很简单
如果线程因为一个无法捕获的异常而终止,可以使用一个实现了接口 Thread.UncaughtExceptionHandler 的类来进行着手处理。
套路很简单,就几个步骤
- 获取异常日志
- 格式化异常日志
- 保存异常日志到本地文件
- 退出崩溃的App