不啰嗦直接上代码,大家请看
public class CrashHandlerManager {
private static CrashHandlerManager instance;
private static Context mContext;
private CrashHandlerManager(){}
public static CrashHandlerManager getInstance(Context context){
if(instance==null){
mContext=context.getApplicationContext();
instance=new CrashHandlerManager();
}
return instance;
}
public void init(){
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread t, Throwable e) {
handleException(e);
//判断当前线程是否是主线程
if(t== Looper.getMainLooper().getThread()){
handleMainThread(e);
}
}
});
}
private void handleMainThread(Throwable e) {
while (true) {
try {
Looper.loop();
} catch (Throwable throwable) {
handleException(throwable);
}
}
}
private void handleException(Throwable e) {
//写入错误日志
//上传日志
}
}
大家很容易就看懂了这个类,保证应用永不崩溃关键在于handleMainThread这个方法。一旦主线程中出现异常就会导致Looper.loop无法正常轮询,看过源码的都知道Looper.loop是执行在ActivityThread的main方法中,只会执行一次,而Looper.loop不能正常轮询就会导致应用崩溃。其中利用Looper.loop是一个阻塞方法的特性,我们可以给它外面套上一层无限循环,一旦出错就会重新启动轮询。
如果想了解Thread.setDefaultUncaughtExceptionHandler为什么可以阻止应用crash,可以查看前一篇文章
通过Thread.setDefaultUncaughtExceptionHandler阻止程序崩溃的源码解析
最后关于handleException的处理
由于各个公司对错误信息处理级别不同,针对错误数据的封装也会各不一样,我只是提一点个人小建议和心得。
1.把错误信息做相应的拆分和拼装,生成规定格式的错误数据,写入日志文件,日志文件可以是区间日志也可以是即刻日志(因为错误信息要分等级,如果是重大bug需要及时上传,并通过短信和邮件及时通知开发人员)
2.存储当前设备信息(用户,厂商,系统,版本)到错误日志
3.既然本地有错误日志肯定要上传,不过上传的间隔肯定要控制,毕竟上传耗费性能(看你们后台需要刷新错误日志的间隔,)
4.上传完成记得及时清除
5.后台构建错误监控模块(不仅仅针对应用的bug也有可能是部分接口功能异常等),针对重大bug,对应用bug功能及时进行动态屏蔽(对应用内部的功能做接口控制),然后用热修复或者应用更新解决问题。