UncaughtExceptionHandler捕获程序异常退出并做相应操作

   UncaughtExceptionHandler介绍

  可以为任何一个Thread设置一个UncaughtExceptionHandler。
  当然也可以为所有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());
	}

}


另外可以在异常回调中,增加自己的处理业务。

  谢谢。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值