Android app一崩溃主要看的还是LOG,获取LOG的主要途径就是Thread.UncaughtExceptionHandler接口,这个接口会在程序崩溃后捕捉到异常返回,但是我们有时候需要的是跟我们在电脑上调试看到的LOG一样,Thread.UncaughtExceptionHandler返回的是你程序出错的方法的地方,如果一个程序的方法里面有很多行,估计还是效率低;这时候就需要如下方式对崩溃日志进行补充。
PrintWriter printWriter = new PrintWriter(fileWriter);
e.printStackTrace(printWriter);//e:异常类
printWriter.flush();
使用方法:
public class MyApplication extends FrameApplication <span style="color:#ff0000;">implements OnSaveErrorLogListener</span> {
@Override
public void onCreate() {
super.onCreate();
new CaughtExceptionTool().init(this, this);
}
@Override
public void onSaveErrorLogSuccess(File file) {
<span style="color:#ff0000;">//你可以上传文件到服务器、发送邮件到自己的Email(Email工具类我博客里面也有)</span>
}
@Override
public void onSaveErrorLogFail(String error) {
}
}
异常处理工具类:
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import cn.elvetrees.frame.utils.app.PathTool;
/**
* Created by ElveTrees on 2016/9/6.
* 捕捉异常工具
*/
public class CaughtExceptionTool implements Thread.UncaughtExceptionHandler {
private Context context;
//线程超时操作
private Future<?> future;
//保存日志的文件夹
private String folderName = "ErrorLog";
//日期格式化
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
//保存日志的文件名
private String fileName = simpleDateFormat.format(Calendar.getInstance().getTime());
//时间
private String time = simpleDateFormat.format(Calendar.getInstance().getTime());
//文件保存格式
private String fileType = ".txt";
//写入的文字结果
//保存错误日志监听
private OnSaveErrorLogListener onSaveErrorLogListener;
//保存日志超时线程池
private ExecutorService threadPool = Executors.newSingleThreadExecutor();
//捕捉异常对象类
private Thread.UncaughtExceptionHandler uncaughExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
public CaughtExceptionTool() {
}
/**
* 初始化
*
* @param context
*/
public void init(Context context) {
this.context = context;
//设置捕捉异常监听
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 初始化
*
* @param context
* @param onSaveErrorLogListener 保存奔溃日志的回调函数
*/
public void init(Context context, OnSaveErrorLogListener onSaveErrorLogListener) {
this.context = context;
this.onSaveErrorLogListener = onSaveErrorLogListener;
//设置捕捉异常监听
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 初始化
*
* @param context
* @param folderName 保存奔溃日志的文件夹名
* @param fileName 保存奔溃日志的文件名
* @param fileType 保存奔溃日志的文件后缀名
* @param onSaveErrorLogListener 保存奔溃日志的回调函数
*/
public void init(Context context, String folderName, String fileName, String fileType, OnSaveErrorLogListener
onSaveErrorLogListener) {
this.context = context;
this.folderName = folderName;
this.fileName = fileName;
this.fileType = fileType;
this.onSaveErrorLogListener = onSaveErrorLogListener;
//设置捕捉异常监听
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 获取奔溃异常
*
* @param thread
* @param ex
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.i("ElveTrees", this.getClass().getSimpleName() + obtainDeviceInfo() + "\n uncaughtException :" +
ex.toString());
if (PathTool.isExistSDCard()) {
final File file = new File(PathTool.createFilePath(PathTool.getSDCardPath() + File.separator +
folderName, fileName + fileType));
//保存错误的日志
saveErrorInfo(obtainDeviceInfo(), file, ex);
future = threadPool.submit(new Runnable() {
public void run() {
if (onSaveErrorLogListener != null) {
onSaveErrorLogListener.onSaveErrorLogSuccess(file);
}
}
});
if (!future.isDone()) {
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
}
uncaughExceptionHandler.uncaughtException(thread, ex);
} else {
if (onSaveErrorLogListener != null) {
onSaveErrorLogListener.onSaveErrorLogFail("You Sdcard is not exist!");
}
Log.e("ElveTrees", this.getClass().getSimpleName() + " You Sdcard is not exist! ");
}
}
/**
* 获取设备信息
*
* @return
*/
private String obtainDeviceInfo() {
StringBuilder sb = new StringBuilder();
//项目信息
sb.append("\n[==Application Information==]").append('\n');
PackageManager packageManager = context.getPackageManager();
ApplicationInfo ai = context.getApplicationInfo();
//项目名字
sb.append("Application Name : ").append(packageManager.getApplicationLabel(ai)).append('\n');
try {
PackageInfo pi = packageManager.getPackageInfo(ai.packageName, 0);
//项目版本号
sb.append("Application Version Code: ").append(pi.versionCode).append('\n');
//项目版本名
sb.append("Application Version Name: ").append(pi.versionName).append('\n');
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
//设备信息
sb.append('\n').append("[==Device Information==]").append('\n');
//手机品牌
sb.append("Brand: ").append(Build.BRAND).append('\n');
//设备名
sb.append("Device: ").append(Build.DEVICE).append('\n');
//手机版本
sb.append("Version Code: ").append(Build.DISPLAY).append('\n');
//指纹
sb.append("Fingerprint: ").append(Build.FINGERPRINT).append('\n');
//制造商
sb.append("Manufacturer: ").append(Build.MANUFACTURER).append('\n');
//产品名
sb.append("Product: ").append(Build.PRODUCT).append('\n');
return sb.toString();
}
/**
* 同步保存错误日志
*
* @param deviceInfo 设备信息
* @param file 保存错误信息的文件
* @param ex 保存错误信息
*/
private synchronized void saveErrorInfo(String deviceInfo, File file, Throwable ex) {
synchronized (file) {
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
PrintWriter printWriter = null;
try {
fileWriter = new FileWriter(file);
bufferedWriter = new BufferedWriter(fileWriter);
printWriter = new PrintWriter(fileWriter);
//拼接应用、设备信息和错误Log
bufferedWriter.append(time).append(" ").append("Error").append('/').append("Log").append("
").append(deviceInfo).append("\n [==Error information==]\n").append(ex.toString());
bufferedWriter.flush();
ex.printStackTrace(printWriter);
printWriter.flush();
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
closeWriter(fileWriter);
closeWriter(bufferedWriter);
closeWriter(printWriter);
}
}
}
/**
* 关闭写入流通道
*
* @param closeable
*/
public static void closeWriter(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ioe) {
Log.i("ElveTrees", CaughtExceptionTool.class.getClass().getSimpleName() + " " + ioe.toString());
}
}
}
}
保存日志监听类:
import java.io.File;
/**
* Created by ElveTrees on 2016/9/6.
* 保存错误日志的监听
*/
public interface OnSaveErrorLogListener {
/**
* 保存错误日志成功回调函数
*
* @param file 保存错误日志的文件
*/
void onSaveErrorLogSuccess(File file);
/**
* 保存错误日志失败的回调函数
*
* @param error 错误信息
*/
void onSaveErrorLogFail(String error);
}