UncaughtExceptionHandler介绍
可以为任何一个Thread设置一个UncaughtExceptionHandler。
当然也可以为所有Thread设置一个默认的UncaughtExceptionHandler,通过调用Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法,这样设置后,可以catch到所有的线程的Exception.
当然也可以为所有Thread设置一个默认的UncaughtExceptionHandler,通过调用Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法,这样设置后,可以catch到所有的线程的Exception.
实现接口uncaughtException
实现Thread.UncaughtExceptionHandler接口的void uncaughtException(Thread t, Throwable e)方法。如果不设置一个Handler,那么单个Thread的Handler是null。但是,如果这个单个线程是ThreadGroup中的一个Thread,那么这个线程将使用ThreadGroup的UncaughtExceptionHandler。ThreadGroup自身已经实现了Thread.UncaughtExceptionHandler接口。自定义CrashHandler
demo如下:
public class LauncherCrashHandler implements UncaughtExceptionHandler {
private final static String TAG = "LauncherCrashHandler";
private static LauncherCrashHandler instance = new LauncherCrashHandler();
private Context mContext;
/**
* 单例模式
* @return
*/
public static LauncherCrashHandler getInstance(){
return instance;
}
/**
* 设置自定义Crash处理
* @param context
*/
public void setCrashHandler(Context context){
mContext = context;
Thread.setDefaultUncaughtExceptionHandler(this);
LogHelper.releaseLog(TAG, "--setCrashHandler");
}
/**
* 异常发生时,系统回调的函数,这里负责存crash信息
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (CrashUtil.saveCrashInfo(mContext)) {
LogHelper.releaseLog(TAG, "--start kill");
// 退出
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
}
将crash处理方法封装CrashUtil
demo如下:
public class CrashUtil {
private final static String TAG = "CrashUtil";
private final static String LAUNCHER_CRASH_TIME_SAVE = "launcher_crash_time_save";
private final static String CRASH_TIME_SEPARATOR = "&"; // crash 时间分隔符
private final static int MAX_MINUTES = 3; // 统计该分钟内crash次数
private final static String ACTION_BUGREPORT = "tv.whaley.bugreport.messagehub"; // 系统日志上报action
private final static String BUGREPORT_KEY = "Content"; // 系统日志上报Key
private final static String BUGREPORT_VALUE = "EMERGENCYSYM"; // 系统日志上报参数
private final static String ACTION_EMERGENCY = "globalmenu.action.applaunch"; // 启动灾难应急页面
private final static String EMERGENCY_KEY = "Data";
private final static String EMERGENCY_VALUE = "page=emergency";
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static boolean saveCrashInfo(final Context context){
String crashedInfo = getGlobalData(LAUNCHER_CRASH_TIME_SAVE);
if(TextUtils.isEmpty(crashedInfo)){ // 无crash信息
saveCurrentCrashTime();
LogHelper.releaseLog(TAG, "--there is no crash Info,save currenTime to crash Info");
return true;
}
String[] crashedArr = null;
try {
crashedArr = crashedInfo.split(CRASH_TIME_SEPARATOR);
} catch (Exception e) {
e.printStackTrace();
LogHelper.releaseLog(TAG, "--split crash time has an Exception");
return true;
}
if(null != crashedArr && crashedArr.length > 0){
String currentTime = getSystemTime();
StringBuilder strBuilder = new StringBuilder();
switch (crashedArr.length) {
case 1:
if(getSecondsBetweenTime(currentTime, crashedArr[0]) <= (MAX_MINUTES *60)){ // 间隔小于阈值,保存之前
strBuilder.append(crashedArr[0]).append(CRASH_TIME_SEPARATOR).append(currentTime);
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, strBuilder.toString());
LogHelper.releaseLog(TAG, "--length is 1 and case 1, save crash time--"+strBuilder.toString());
}
else{ // 只保存当前
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, currentTime);
LogHelper.releaseLog(TAG, "--length is 1 and case 2, save crash time--"+currentTime);
}
break;
case 2:
if(getSecondsBetweenTime(currentTime, crashedArr[0]) > (MAX_MINUTES *60)){
if(getSecondsBetweenTime(currentTime, crashedArr[1]) > (MAX_MINUTES *60)){
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, currentTime);
LogHelper.releaseLog(TAG, "--length is 2 and case 3, save crash time--"+currentTime);
}
else{
strBuilder.append(crashedArr[1]).append(CRASH_TIME_SEPARATOR).append(currentTime);
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, strBuilder.toString());
LogHelper.releaseLog(TAG, "--length is 2 and case 4, save crash time--"+strBuilder.toString());
}
}
else{
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, "");
// send broadcaset
LogHelper.releaseLog(TAG, "--start broadcast");
sendBugReportBroadcast(context);
startEmergencyActivity(context);
LogHelper.releaseLog(TAG, "--length is 2 and case 5, send braodcast");
}
break;
default:
break;
}
return true;
}
else{
saveCurrentCrashTime();
LogHelper.releaseLog(TAG, "--crashedArr is empty");
return true;
}
}
/**
* 启动灾难应急页面
* @param context
*/
public static void startEmergencyActivity(Context context){
if(null == context){
LogHelper.releaseLog(TAG, "--sendEmergencyBroadcast context is null ,return");
return;
}
Intent intent = new Intent();
intent.setAction(ACTION_EMERGENCY);
intent.putExtra(EMERGENCY_KEY, EMERGENCY_VALUE);
context.startActivityAsUser(intent,UserHandle.CURRENT);
LogHelper.releaseLog(TAG, "--startEmergencyActivity");
}
/**
* 发送系统日志上报广播
* @param context
*/
public static void sendBugReportBroadcast(Context context){
if(null == context){
LogHelper.releaseLog(TAG, "--sendBugReportBroadcast context is null, return");
return;
}
Intent intent = new Intent();
intent.setAction(ACTION_BUGREPORT);
intent.putExtra(BUGREPORT_KEY, BUGREPORT_VALUE);
context.sendBroadcastAsUser(intent, UserHandle.CURRENT);
LogHelper.releaseLog(TAG, "--sendBugReportBroadcast");
}
/**
* 返回两个时间间隔的秒数
* @param timeNow
* @param timeBefore
* @return
*/
public static int getSecondsBetweenTime(String timeNow, String timeBefore){
int seconds = 0;
try {
Date date1 = sdf.parse(timeNow);
Date date2 = sdf.parse(timeBefore);
seconds = (int) ((date1.getTime() - date2.getTime()) / 1000);
} catch (ParseException e) {
e.printStackTrace();
LogHelper.releaseLog(TAG, "--getSecondsBetweenTime has an Exception");
}
LogHelper.releaseLog(TAG, "--getSecondsBetweenTime--timeNow-"+timeNow+"--timeBefore-"+timeBefore+"--interval seconds-"+seconds);
return seconds;
}
public static String getSystemTime() {
Date date = new Date();
return sdf.format(date);
}
/**
* 存当前crash时间
*/
private static void saveCurrentCrashTime(){
String currentTime = getSystemTime();
saveGlobalData(LAUNCHER_CRASH_TIME_SAVE, currentTime);
LogHelper.releaseLog(TAG, "--saveCurrentCrashTime--"+currentTime);
}
private static void saveGlobalData(String key, String value){
Common.getGlobalData().setGlobalData(key, value);
}
private static String getGlobalData(String key){
return Common.getGlobalData().getGlobalData(key);
}
}
注释:以上逻辑是当程序在3min内crash3次时,发送系统日志上报,同时启动灾难应急页面,可以提醒用户,进行恢复出厂设置或重新启动。
在Application中初始化异常处理
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
GeneralHelper.init(getApplicationContext());
LauncherCrashHandler.getInstance().setCrashHandler(getApplicationContext());
}
}
另外可以在异常回调中,增加自己的处理业务。
谢谢。