大家都知道,在开发程序时,很难做到不会crash,程序在crash后我们就要分析其原因,那么首先就得统计crash信息。
本篇文章将介绍程序在crash后,如何获取crash的信息。
创建CrashHandler
package com.crash.xxx.crashhandlertest;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by xxx on 2016/8/19.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final boolean DEBUG=true;
private static final String TAG="CrashHanler";
private static final String PATH=Environment.getExternalStorageDirectory().getPath()+"/crashHandlerTest/crash_log/";
private static final String FILE_NAME="crash_";
private static final String FILE_NAME_SUFFIX=".trace";
private static CrashHandler mInstance=new CrashHandler();
private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler;
private Context mContext;
private CrashHandler(){
}
public static CrashHandler getInstance(){
return mInstance;
}
public void init(Context context){
mUncaughtExceptionHandler=Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
mContext=context.getApplicationContext();
}
/**
* 当程序中有未捕捉的异常,系统自动调用此方法;
* thread为出现异常的线程,ex为未捕捉的异常
* @param thread
* @param ex
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
//将导出的异常写入SD卡中
dumpExceptionToSDCard(ex);
} catch (IOException e) {
e.printStackTrace();
}
ex.printStackTrace();
//如果系统提供了异常处理,则交给系统去结束程序,否则由自己的程序结束自己
if (mUncaughtExceptionHandler!=null){
mUncaughtExceptionHandler.uncaughtException(thread,ex);
}else{
Process.killProcess(Process.myPid());
}
}
public void dumpExceptionToSDCard(Throwable ex) throws IOException{
//如果sd卡存在,则将异常写入sd卡中
if (!Environment.getExternalStorageState().endsWith(Environment.MEDIA_MOUNTED)){
if (DEBUG){
Log.w(TAG,"sdcard unmounted,skip dump exception");
return;
}
}
File dir=new File(PATH);
if (!dir.exists()){
dir.mkdirs();
}
long current=System.currentTimeMillis();
String time=new SimpleDateFormat("yyyy-MM-dd").format(new Date(current));
File file=new File(PATH+FILE_NAME+time+FILE_NAME_SUFFIX);
try {
PrintWriter pw=new PrintWriter(new BufferedWriter(new FileWriter(file)));
pw.println(time);
//写入手机信息
dumpPhoneInfo(pw);
pw.println();
//写入崩溃信息
ex.printStackTrace(pw);
pw.close();
} catch (Exception e) {
e.printStackTrace();
if (DEBUG){
Log.e(TAG,"写入失败"+e);
}
}
}
public void dumpPhoneInfo(PrintWriter pw) throws PackageManager.NameNotFoundException{
PackageManager pm=mContext.getPackageManager();
PackageInfo pi=pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES);
pw.println("APP Version:");
pw.print(pi.versionName);
pw.print("_");
pw.println(pi.versionCode);
//android version code
pw.print("OS version: ");
pw.print(Build.VERSION.RELEASE);
pw.print("_");
pw.println(Build.VERSION.SDK_INT);
//phone makes vendor
pw.print("Vendor: ");
pw.println(Build.MANUFACTURER);
//phone model
pw.print("Model: ");
pw.println(Build.MODEL);
//CPU ABI
pw.print("CPU ABI: ");
pw.println(Build.CPU_ABI);
}
//将crash日志上传到服务器
public void upLoadExceptionToServer(){
}
}
在AppLication初始化时为线程配置CrashHandler
@Override
public void onCreate() {
super.onCreate();
CrashHandler crashHandler=CrashHandler.getInstance();
crashHandler.init(this);
}
在清单文件中注册创建的AppLication,并添加所需的权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.Write_EXTERNAL_STORAGE"/>
测试
在MainActivity中创建一个Button,为其添加点击事件,在监听回调中抛一个自定义异常。
@Override
public void onClick(View v) {
if (v.getId()==R.id.btn_click){
throw new RuntimeException("自定义运行时异常");
}
}