您的位置:首页 > 移动开发 > Android开发

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

2017-01-24 16:46 387 查看
在开发过程中,我们经常面临的问题是解决造成程序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版本等,一图胜千言:





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

/**
* Created by ShiXiuwen on 2017/1/14.
* <p>
* 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.
* <p>
* 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收集方法,如客官您有更好的建议,欢迎留言告知,当感激不尽~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐