将log保存到本地

时间:2020-12-02 02:37:38

app在现场测试,发生crash时无法从logcat找到原因,如能将发生错误时的log记录下来,对debug非常有利.
关键接口:Thread.UncaughtExceptionHandler用来捕获运行时未被程序捕获的异常
关键方法
@Override
public void uncaughtException(Thread thread, Throwable ex) {
//错误发生后要执行的操作,如保存错误报告
//这个是最关键的函数,当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法
//thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。报告
}
通过Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上即可.

下面是收集log的工具类的范例代码:

public class LogCollectionUtil implements UncaughtExceptionHandler {

private Context mContext;

private static final String SDCARD_PATH = Environment
.getExternalStorageDirectory().toString();

// 系统默认的异常处理(默认情况下系统会终止当前的异常程序)
private UncaughtExceptionHandler mUncaughtExceptionHandler;

private CopyOfLogCollectionUtil2() {
};

private static CopyOfLogCollectionUtil2 instance = new CopyOfLogCollectionUtil2();

public static CopyOfLogCollectionUtil2 getLogCollectionUtil() {
return instance;
}

/**
* 初始化,注册Context对象, 获取系统默认的UncaughtException处理器, 设置该CrashHandler为程序的默认处理器
*
* @param context
*/

public void setCrashHandler(Context context) {
mContext = context;
Thread.setDefaultUncaughtExceptionHandler(this);
}

/**
* 当uncaughtException发生时会转入该函数处理
*/

@Override
public void uncaughtException(Thread thread, Throwable ex) {
dumpExceptionToSDCard(mContext, ex);
showToast(mContext, "我挂了...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 如果系统提供了默认异常处理器,交给系统结束我们的程序,否则自己结束自己
if (mUncaughtExceptionHandler != null) {
mUncaughtExceptionHandler.uncaughtException(thread, ex);
} else {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}

/**
* save exception info to sd
*
* @param context
* @param ex
* @return
*/


private void dumpExceptionToSDCard(Context context, Throwable ex) {

String fileName = createFile();

try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
fileName)));
dumpPhoneInfo(pw);
pw.println();
dumpCrashInfo(ex, pw);
pw.close();
} catch (Exception e) {
Log.e("dd", "dump crash info failed");
}
}

/**
* create file in SDCard
*
* @return
*/

private String createFile() {
String fileName;
File dir = null;
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
dir = new File(SDCARD_PATH + File.separator + "crash" + File.separator);
if (!dir.exists()) {
dir.mkdir();
}
}
return fileName = dir.toString() + File.separator
+ parseTime(System.currentTimeMillis()) + ".log";
}

/**
* collect device info
*
* @param pw
* @throws NameNotFoundException
*/

private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
PackageManager pm = mContext.getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(mContext.getPackageName(),
PackageManager.GET_ACTIVITIES);
pw.println("App version: " + packageInfo.versionName + '_'
+ packageInfo.versionCode);
pw.println("OS version: " + Build.VERSION.RELEASE + '_'
+ Build.VERSION.SDK_INT);
// The manufacturer of the product/hardware.
pw.println("Vendor: " + Build.MANUFACTURER);
pw.println("Model: " + Build.MODEL);
pw.println("Product: " + Build.PRODUCT);
pw.println("Brand: " + Build.BRAND);
pw.println("Display: " + Build.DISPLAY);
pw.println("Device: " + Build.DEVICE);
pw.println("CPU abi: " + Build.CPU_ABI);
pw.println("Fingerprint: " + Build.FINGERPRINT);
}

/**
* collect log info
*
* @param throwable
* @param pw
*/

private void dumpCrashInfo(Throwable throwable, PrintWriter pw) {
throwable.printStackTrace(pw);
}

/**
* format time
*
* @param milliseconds
* @return
*/

private String parseTime(long milliseconds) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setTimeZone(TimeZone.getDefault());
String times = format.format(new Date(milliseconds));
return times;
}

/**
* give user tips
*
* @param context
* @param msg
*/

private void showToast(final Context context, final String msg) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
Looper.loop();
}
}).start();
}

}

使用时将以上代码放到你的包里,将如下代码添加到application类的onCreate()方法里即可使用(放在activity的onCreate()方法里也是可以的,这样只能捕获这个activity的crash,定义在application类里可以捕获app所有线程的异常.).
LogCollectionUtil mLogCollection=LogCollectionUtil.getLogCollectionUtil();
mLogCollection.setCrashHandler(this);
发生crash后,在你手机里的crash文件夹下寻找log.