问题
android开发或者运行过程中难免会出现Crash,如何持久化崩溃日志便于重新定位
知识点补充
Java中的Thread定义了一个接口UncaughtExceptionHandler
用于处理未捕获的异常导致线程的终止(值得注意:已经被捕获的异常是捕获不到的)。
- 当应用crash的时候,就会执行
UncaughtExceptionHandler.uncaughtException
方法 ,该方法可以获取到异常的信息。 - 通过
Thread.setDefaultUncaughtExceptionHandler
方法可以设置线程的默认异常处理器。 - 通过
Thread.getDefaultUncaughtExceptionHandler();
方法可以拿到系统默认的异常处理对象(Android默认的是RuntimeInit.java
内部类KillApplicationHandler
的实例对象)。
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
private final LoggingHandler mLoggingHandler;
public KillApplicationHandler(LoggingHandler loggingHandler) {
this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
ensureLogging(t, e);
if (mCrashing) return;
mCrashing = true;
if (ActivityThread.currentActivityThread() != null) {
ActivityThread.currentActivityThread().stopProfiling();
}
ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
} catch (Throwable t2) {
if (t2 instanceof DeadObjectException) {
} else {
try {
Clog_e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
}
}
} finally {
Process.killProcess(Process.myPid());
System.exit(10);
}
}
解决方案
在Application
中调用init()
方法即可
具体实现步骤
- 获得系统默认的异常处理对象
- 替换当前系统默认的异常处理对象,为自行实现的异常处理对象
- 在执行完后,再调用原系统默认的异常处理对象,执行原有操作
public final class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final CrashHandler mCrashHandler = new CrashHandler();
private static Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
private static Context mContext;
private static final String FILE_NAME_SUFFIX = ".txt";
private CrashHandler() {
}
public static void init(@NonNull Context context) {
//获得默认的系统异常的异常处理对象
mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(mCrashHandler);
mContext = context.getApplicationContext();
}
/**
* 当程序中有未被捕获的异常,
* 系统将会调用这个方法
*
* @param t 出现未捕获异常的线程
* @param e 得到异常信息
*/
@Override
public void uncaughtException(Thread t, Throwable e) {
try {//自行处理:保存本地
File file = dealException(t, e);
} catch (Exception e1) {
e1.printStackTrace();
} finally { //交给系统默认程序处理
if (null != mDefaultExceptionHandler) {
mDefaultExceptionHandler.uncaughtException(t, e);
}
}
}
/**
* 导出异常信息到本地
*
* @param e
*/
private File dealException(Thread t, Throwable e) throws Exception {
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
File f = new File(mContext.getCacheDir().getAbsoluteFile(), "crash_info");
if (!f.exists()) {
f.mkdirs();
}
File crashFile = new File(f, time + FILE_NAME_SUFFIX);
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(crashFile)));
pw.println(time);
pw.println("Thread: " + t.getName());
pw.println(getPhoneInfo());
e.printStackTrace(pw); //写入crash堆栈
pw.flush();
pw.close();
return crashFile;
}
/**
* 用户信息
*
* @return
*/
private String getPhoneInfo() {
return "";//todo 自定义需要拼接的用户信息
}
}
网友评论