android开发技巧-记录未捕获的crash异常日志
2016-10-09 15:39
441 查看
提出问题
开发过程中,在自测和交付测试的过程中会遇到发生crash但是无法捕获异常的情况。比如:一个人在厕所无聊瞎点,突然就crash了。你不可能带着线、电脑和手机在厕所瞎点的吧,所以你看不到电脑上crash的日志,毕竟是瞎点,那么crash的步骤你并不清楚。如果crash日志没有,那么就尴尬了。就像明明有个老王,但你却没有看清他的脸,是不是好气?解决方案
既然有了老王,就需要在家里安装个摄像头,再来的时候,一定能记录他的外貌。而UncaughtExceptionHandler就是能够帮你记录老王面貌的工具。大多数人都把他封装为CrashHandler。打包发布的apk当然也可以将捕获的UncaughtExceptionHandler上传到公司的服务器分析。一般都选择了一种友盟分析的sdk集成来做,人家好的东西不花钱,拿来就用。明确需求
需求很简单,就是告诉我问题出在哪里,即:where,当然能带上设备信息,即:what,和发生的时间 when会更好,因为你搞不清到底有几个老王来了几次?方案执行
编写相关异常捕获类CrashHandler通过实现UncaughtExceptionHandler,先通过Thread的getDefaultUncaughtExceptionHandler静态方法将原来系统提供的UncaughtExceptionHandler保存为mDefaultHandler,然后通过Thread静态方法
setDefaultUncaughtExceptionHandler设置当前Tread的处理Handler为crashHandler,当Thread有异常时回调crashHandler uncaughtException方法,先将错误日志记录在存储上,然后再通过原来系统提供的mDefaultHandler抛出异常。
public class CrashHandler implements UncaughtExceptionHandler { /** 获取CrashHandler实例 ,单例模式 */ public static CrashHandler getInstance() { if (crashHandler == null) { synchronized (CrashHandler.class) { crashHandler = new CrashHandler(); } } return crashHandler; } // 系统默认的UncaughtException处理类实例 private Thread.UncaughtExceptionHandler mDefaultHandler; //CrashHandler静态实例 private static CrashHandler crashHandler; // 程序的Context对象 private Context mContext; //时间输出格式化 private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("_yyyy_MM_dd_HH_mm_ss"); /** 保证只有一个CrashHandler实例 */ private CrashHandler() { } /** * 初始化 * * @param context */ public void init(Context context) { mContext = context; // 获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); // 设置该CrashHandler为程序的默认处理器 Thread.setDefaultUncaughtExceptionHandler(this); } /** * 调用Thread.setDefaultUncaughtExceptionHandler(this);后,this实现了 * UncaughtExceptionHandler,所以crash会进入到这里的回调。 * 当UncaughtException发生时会转入该重写的方法来处理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { if (thread == null || ex == null || mDefaultHandler == null) { System.exit(0); return; } File savePathFile = getLogFilePath(mContext); if (savePathFile == null) { //抛出异常 mDefaultHandler.uncaughtException(thread, ex); return; } String logMessage = String .format("CustomUncaughtExceptionHandler.uncaughtException: Thread %d Message %s", thread.getId(), ex.getMessage()); PrintWriter printWriter = null; try { printWriter = new PrintWriter(new FileWriter(savePathFile, true)); logMessage = String.format("%s\r\n\r\n%s\r\n\r\nThread: %d\r\n\r\nMessage:\r\n\r\n%s\r\n\r\nStack Trace:\r\n\r\n%s", geDeviceInfo(mContext), new Date(), thread.getId(), ex.getMessage(), Log.getStackTraceString(ex)); printWriter.print(logMessage); printWriter.print("\n\n-------------------------------------------------\n\n"); } catch (Throwable tr2) { //最后回抛出异常,所以这里就可以不用处理了。 } finally { if (printWriter != null) { printWriter.close(); } } mDefaultHandler.uncaughtException(thread, ex); } /** * * 获取设备信息 * * @param context * @return String 设备信息 */ public String geDeviceInfo(Context ctx) { StringBuffer deviceInfo = new StringBuffer(); deviceInfo.append(android.os.Build.MODEL).append("/"); deviceInfo.append(android.os.Build.VERSION.SDK).append("/"); deviceInfo.append(getVersionName(ctx)); return deviceInfo.toString(); } /** * * 获取应用版本号 * * @param context * @return String 应用版本号 */ public String getVersionName(Context context) { String version = ""; if(context == null) { return version; } try { // 获取packagemanager的实例 PackageManager packageManager = context.getPackageManager(); // getPackageName()是你当前类的包名,0代表是获取版本信息 if(packageManager != null) { PackageInfo packInfo; packInfo = packageManager.getPackageInfo(context.getPackageName(), 0); if(packInfo != null) { version = packInfo.versionName; } } } catch (Exception e) { } return version; } /** * * 获取日志保存路径 * * @param context * @return String 日志保存路径 */ public File getLogFilePath(Context ctx) { String sdStatus = Environment.getExternalStorageState(); if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { return null; } String pathName = Environment.getExternalStorageDirectory().getPath() + "/Android/data/" + ctx.getPackageName() + "/files/error/" + android.os.Build.MODEL + "_" + getVersionName(ctx) + simpleDateFormat.format(new Date()) +".log"; File path = new File(pathName); if (!path.getParentFile().exists()) { path.getParentFile().mkdirs(); } return path; } }
初始化CrashHandler
public class MyApplication extends Application{ @Override public void onCreate() { //如果是调试的apk,就初始化 if(BuildConfig.DEBUG){ CrashHandler.getInstance().init(this); } } }
相关文章推荐
- Android全局捕获崩溃异常记录日志保存至本地并定时删除
- android应用开发中收集的异常日志解决方法记录
- Windows Phone 实用开发技巧(22):使用日志记录当前信息与异常信息
- Android开发之处理崩溃异常和记录日志
- Android全局捕获崩溃异常记录日志保存至本地并定时删除
- Android全局捕获崩溃异常记录日志保存至本地并定时删除
- Windows Phone 实用开发技巧(22):使用日志记录当前信息与异常信息 推荐
- android app记录运行日志 捕获奔溃异常 ,存储日志到文件
- android基础学习之捕获异常并记录日志
- android app记录运行日志 捕获奔溃异常 ,存储日志到文件
- Android全局捕获崩溃异常记录日志保存至本地并定时删除
- Android 未捕获异常crash崩溃日志的截取
- Android log日志异常捕获信息收集类
- Android crash 日志捕获
- IOS开发笔记(5)程序异常crash捕获与拦截
- Android实现将日志、异常记录到本地的方法
- Android开发之全局异常捕获完美闪退APP专题
- 怎样实现了捕获应用中的日志在android开发中
- android应用开发-------------应用崩溃全局异常捕获处理(UncaughtExceptionHandler)
- Android中处理崩溃异常和记录日志