一.什么是UncaughtExceptionHandler
UncaughtExceptionHandler 是Java Thread类中定义的一个接口,用于处理未捕获的异常导致线程的终止。
当我们的App 停止运行的时候,就会走 UncaughtExceptionHandler的uncaughtException 方法,在该方法中可以获取到异常的信息。
所以,我们通过 setDefaultUncaughtExceptionHandler 该方法来设置线程的默认异常处理器,将异常信息保存到本地或者是上传到服务器,方便我们快速的定位问题。
二.捕获全局异常的工具类
public class NeverCrash {
private CrashHandler mCrashHandler;
private static NeverCrash mInstance;
private NeverCrash() {
}
private static NeverCrash getInstance() {
if (mInstance == null) {
synchronized (NeverCrash.class) {
if (mInstance == null) {
mInstance = new NeverCrash();
}
}
}
return mInstance;
}
public static void init(CrashHandler crashHandler) {
getInstance().setCrashHandler(crashHandler);
}
/**
* @author Longchengbin
* @description 捕获异常的回调操作
* @since 2020-8-3 08:54
**/
private void setCrashHandler(CrashHandler crashHandler) {
mCrashHandler = crashHandler;
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
for (; ; ) {
try {
Looper.loop();
} catch (Throwable e) {
LogUtils.e(TimeUtil.getSystem() + "程序崩溃原因:" +e+"\n"+e.toString()+"\n"+e.getMessage()+"\n"+e.getLocalizedMessage());
LogUtils.file("\n"+"程序崩溃原因:");
LogUtils.file(e);
if (mCrashHandler != null) {//捕获异常处理
mCrashHandler.uncaughtException(Looper.getMainLooper().getThread(), e);
}
}
}
}
});
/**
* @author Longchengbin
* @description 设置系统全局异常
* @since 2020-8-3 08:55
**/
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
if (mCrashHandler != null) {//捕获异常处理
mCrashHandler.uncaughtException(t, e);
}
}
});
}
/**
* @author Longchengbin
* @description 异常回调接口
* @since 2020-8-3 08:53
**/
public interface CrashHandler {
void uncaughtException(Thread t, Throwable e);
}
}
TimeUtil
public class TimeUtil {
/**
* 以指定字符串形式返回当前系统时间
*/
public static String getSystem() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
Date date = new Date(System.currentTimeMillis());
String s = format.format(date);
return s;
}
/**
* 时间戳转成指定字符串
*/
public static String long2time(long time, String formatStyle) {
SimpleDateFormat format = new SimpleDateFormat(formatStyle, Locale.getDefault());
Date date = new Date(time);
String s = format.format(date);
return s;
}
/**
* 指定字符串转为时间戳
*
* @param time 指定字符串
* @param formatStyle 字符串格式
*/
public static long time2long(String time, String formatStyle) {
SimpleDateFormat format = new SimpleDateFormat(formatStyle, Locale.getDefault());
Date date;
try {
date = format.parse(time);
} catch (ParseException e) {
date = new Date();//如果格式错误就返回当前时间搓
e.printStackTrace();
Logs.d(e.getMessage());
}
return date.getTime();
}
/**
* 根据一段时间戳返回耗时时间字符
*/
public static String long2time(long time) {
String str = "";
long h = 60 * 60 * 1000;
long m = 60 * 1000;
long s = 1000;
if (time > h) {
long hh = time / h;
long mm = time / m;
long ss = time / s;
str = hh + "小时" + mm + "分钟" + ss + "秒";
} else if (time > m) {
long mm = time / m;
long ss = time / s;
str = mm + "分钟" + ss + "秒";
} else {
long ss = time / s;
str = ss + "秒";
}
return str;
}
}
三.在application中设置初始化工具
private void initCrash() { NeverCrash.init(new NeverCrash.CrashHandler() { @Override public void uncaughtException(Thread t, Throwable e) { showMessage("程序异常请将日志发给研发人员"); } }); }
参考文章:
https://mp.weixin.qq.com/s/66P1Q7QKEBzJ1ORxmiXdJA
https://juejin.im/post/6869644258983608328#heading-4
四.第三方崩溃框架
CustomActivityOnCrash:一款当APP crash的时候自动载入某个Activity的框架
github https://github.com/Ereza/CustomActivityOnCrash
使用:
implementation 'cat.ereza:customactivityoncrash:2.1.0'
添加到 Application
public void onCreate() {
super.onCreate();
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SILENT)
.enabled(false) //default: true
.showErrorDetails(false) //default: true
.showRestartButton(false) //default: true
.trackActivities(true) //default: false
.minTimeBetweenCrashesMs(2000) //default: 3000
.errorDrawable(R.drawable.ic_custom_drawable) //default: bug image
.restartActivity(YourCustomActivity.class) //default: null (your app's launch activity)
.errorActivity(YourCustomErrorActivity.class) //default: null (default error activity)
.eventListener(new YourCustomEventListener()) //default: null
.apply();
}