Android Crash 监控
Crash(应用崩溃)是由于代码异常而导致 App 非正常退出,导致应用程序无法继续使用,所有工作都停止的现象。发生 Crash 后需要重新启动应用(有些情况会自动重启),而且不管应用在开发阶段做得多么优秀,也无法避免 Crash 发生,特别是在 Android 系统中,系统碎片化严重、各 ROM 之间的差异,使 Android 在稳定性方面需要付出更多的代价。
在应用中发生 Crash 具有以下两个特点。
非必现:一般来说 Crash 不是必现的,可能是一个很少使用的场景触发,在开发和测试阶段都没有考虑到,并且是有概率地触发。
原因多,无法系统性解决:导致 Crash 的原因有很多,有代码逻辑缺陷、系统兼容问题、硬件兼容问题,而在应用开发时较少关注到,特别是硬件和 ROM 的兼容性问题,需要特定的机型/ROM 和特定的场景才触发。
因此,要降低 Crash 发生的概率,需要 Crash 监控和发生 Crash 时的堆栈信息,开发者拿到这些信息后分析导致 Crash 的原因并修复。
在 Android 应用中发生的 Crash 有两种类型,Java 层的 Crash 和 Native 层 Crash。这两种Crash 的监控和获取堆栈信息有所不同。接下来介绍发生 Crash 时,如何监控和获取日志。
- Java 层 层 Crash
在 Android 中,Java 虚拟机为每个进程都设置了一个默认 UncaughtExceptionHandler,用于处理本进程中未被try catch的Exception。因此只要实现UncaughtExceptionHandler 接口,并在进程启动时调用 Thread.setDefaultUncaughtExceptionHandler (…)传入自定义的 UncaughtExceptionHandler,当出现没被 catch 的异常时,就会回调 uncaughtException(Thread thread,Throwable ex)方法,可在这里记录 crash 日志,并上报给服务器,也可以执行一些个性化的异常处理操作。
下面是一个实现 Thread.UncaughtExceptionHandler 接口的类:CrashHandler,代码如下
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private static final String CRASH_FILE_NAME = "crash";
String p = "";
private static final String CRASH_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/log/";
private static final String CRASH_FILE_NAME_SUFFIX = ".txt";
private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
private Context mContext;
public void init(Context context) {
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
this.mContext = context;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
dumpExceptionToSDCard(e);
if (mDefaultCrashHandler !=null){
mDefaultCrashHandler.uncaughtException(t,e);
}else {
Process.killProcess(Process.myPid());
}
}
private void dumpExceptionToSDCard(Throwable e) {
File dir = new File(CRASH_FILE_PATH);
if (!dir.exists()) {
dir.mkdirs();
}
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
File file = new File(CRASH_FILE_PATH + CRASH_FILE_NAME + time + CRASH_FILE_NAME_SUFFIX);
try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
pw.println(time);
getPhoneInfo(pw);
pw.println();
// 导出异常的调用栈信息
e.printStackTrace(pw);
pw.close();
} catch (IOException ex) {
Log.e(TAG, ex.toString());
}
}
private void getPhoneInfo(PrintWriter pw) {
// 上报手机信息 版本 等等
}
}
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
CrashHandler crashHandler = new CrashHandler();
crashHandler.init(this);
}
}
当发生 Crash 后,CrashHandler 类通过回调方法 uncaughtException,在这里可以拿到错误的信息,也可以上报更多的辅助数据去分析。而 CrashHandler 最好是在 AppApplication 中注册,这样就可以监听 Java 层的 Crash,并保存发生 Crash 的错误堆栈,或者根据需求增加一些辅助信息。
上一篇: OCCT中的偏移面 (Geom_OffsetSurface)
下一篇: iOS crash 定位