Android客户端收集Crash信息的常用方法

在开发过程中,我们经常面临的问题是解决造成程序Crash的bug,而解决这些问题的途径无非是通过Crash的时候遗留的log进行分析,快速定位问题发生的原因然后解决问题。大多数时候我们都是在开发过程中进行自测的时候发现问题,这一类的问题发生的时候log信息通常都会显示在控制台上,通过简单分析基本能够得到解决,而真正难以解决的是测试人员在平时测试的时候偶然发现的一个bug,然而又不容易复现,或者是用户使用过程中产生的偶现的Crash,通常这一类问题我们都是无法直接看到Crash发生时的log信息的,解决的方法只能是按照他人提供的操作步骤机械性的进行重复操作,盼着bug能够再现……

针对以上问题,在此提出两种解决思路,当然不是能够直接解决你的Crash的万能代码,而是提供一个在别人手机上发生Crash的时候,你依旧能够获得Crash时产生的log信息,方便开发者定位问题。

针对第二种情况,用户反馈的Crash,在此推荐在你的应用程序中集成腾讯Bugly,这是一款使用十分方便的Crash跟踪工具,集成也十分简单,他们的介绍是:

一种愉悦的开发方式
腾讯Bugly,为移动开发者提供专业的异常上报,运营统计和内测分发解决方案,帮助开发者快速发现并解决异常,同时掌握产品运营动态,及时跟进用户反馈。
腾讯bugly接入首页

使用之后当用户程序由于异常产生Crash的时候,该Crash的log信息会直接上报到你注册的应用中,和在控制台中看到的Crash信息无异,同时提供其他一系列相关数据,包括产生Crash的手机型号,SDK版本等,一图胜千言:

Android客户端收集Crash信息的常用方法_第1张图片

Android客户端收集Crash信息的常用方法_第2张图片

针对第二种情况,身边测试人员反馈的Crash,或者你自己的手机未接入电脑的时候产生的Crash,这些情况下你都无法直接在控制台上看到log信息,此时提供的解决方案是将发生Crash时候的log信息直接存到手机里,该log信息以文本形式存储,可以直接打开查看,Android为我们提供了UncaughtExceptionHandler这个类来进行该操作,至于这个类的具体介绍网上有很多博文,请自行百度,在此提供工具类。可直接使用,使用方法见后文。

/**
 * Created by ShiXiuwen on 2017/1/14.
 * 

* Description:将程序的Crash信息写进文件 */ public class Utils_CrashHandler implements Thread.UncaughtExceptionHandler { private static final String TAG = "Util_CrashHandler"; private Context mContext; private static Utils_CrashHandler INSTANCE = new Utils_CrashHandler(); private Thread.UncaughtExceptionHandler mDefaultHandler; public static Utils_CrashHandler getInstance() { return INSTANCE; } public void init(Context ctx) { mContext = ctx.getApplicationContext(); mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(final Thread t, final Throwable e) { try { Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); e.printStackTrace(printWriter); Throwable cause = e.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); File file = new File(getDiskCacheDir(mContext, "crash"), "crash.log"); if (file.exists() && file.length() > 5 * 1024 * 1024) { // <5M boolean delete = file.delete(); } File folder = new File(getDiskCacheDir(mContext, "crash")); if (folder.exists() && folder.isDirectory()) { if (!file.exists()) { boolean newFile = file.createNewFile(); if(!newFile){ return; } } } else { boolean mkDir = folder.mkdir(); if (mkDir) { boolean newFile = file.createNewFile(); if(!newFile){ return; } } } FileOutputStream fos = new FileOutputStream(file, true); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA); String format = sdf.format(new Date()); byte[] bytes = (format + //追加Crash时间 "\n" + result + //Crash内容 "\n" + "######## ~~~ T_T ~~~ ########" + //分割线 "\n").getBytes(); fos.write(bytes); fos.flush(); fos.close(); } catch (Exception exception) { exception.printStackTrace(); } mDefaultHandler.uncaughtException(t, e); //该代码不执行的话程序无法终止 } /** * @param context context * @param dirName dirName * @return dir */ private String getDiskCacheDir(Context context, String dirName) { String cachePath = null; if ("mounted".equals(Environment.getExternalStorageState())) { File externalCacheDir = context.getExternalCacheDir(); if (externalCacheDir != null) { cachePath = externalCacheDir.getPath(); } } if (cachePath == null) { File cacheDir = context.getCacheDir(); if ((cacheDir != null) && (cacheDir.exists())) { cachePath = cacheDir.getPath(); } } //0/emulate/Android/data/data/com.***.***/crash/crash.log return cachePath + File.separator + dirName; } }

使用方法

在程序的Application类中,直接注册一句代码即可,eg:

/**
 * Created by ShiXiuwen on 2017/1/14.
 * 

* Description:Application 初始化操作 */ public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //初始化CrashHandler收集崩溃信息到本地 Utils_CrashHandler.getInstance().init(this); } }

使用该工具类之后,手机到的Crash信息会被保存在手机的缓存目录中,比如你的项目包名为:

com.mycompanyname.demo

则log文件在手机中的存储路径为:

//0/emulate/Android/data/data/com.mycompanyname.demo/crash/crash.log

不同时间发生的Crash都会保存到该文件中,和控制台中输出的log信息无异。

其实在实际开发过程中还会遇到另外一种情况,那就是系统底层发生Crash,比如你调用了JNI文件而产生的Crash,有时候即使你的手机连接在控制台上也无法打印出log信息,因为该这类Crash发生的时候很可能相关进程会直接被kill掉,导致AndroidStudio清楚了控制台上的log信息,该情况下提供的解决思路是打开系统控制台,使用adb logcat命令抓取你想要的log,这样能够保证log不会被清除,不过该方法信息量有点大,要加上合适的过滤条件或者准确的控制开始及结束来定位(操作之前开始打印log,发生Crash的时候立即按Ctrl+C停止log打印),再或者配合log的时间标识记住大概产生Crash的时候log的打印时间,以此定位具体log信息。adb logcat的具体使用方法推荐博客:

http://blog.csdn.net/tumuzhuanjia/article/details/39555445

以上是本人使用过的log收集方法,如客官您有更好的建议,欢迎留言告知,当感激不尽~

你可能感兴趣的:(Android,android,bug,UncaughtEx,bug收集)