当程序FC时,系统会调用Thread中的接口UncaughtExceptionHandler,调用 uncaughtException(Thread thread, Throwable ex)方法,所以,我们可以实现自己的UncaughtExceptionHandler,实现uncaughtException方法,设置:
Thead.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler)
以此来对崩溃进行处理
在uncaughtException中,做了以下3件事
1.崩溃时的回调
2.收集设备信息与崩溃堆栈信息
3.重启应用
当再次启动应用时,若发现log日志中有内容,可以上传至服务器
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static CrashHandler mInstance;
private Context mContext;
private Class mRestartClass;//崩溃后,重启软件时的Activity,可设置为反馈界面
private OnCrashListener mListener;
private String mLogPath;//崩溃日志的储存路径
private CrashHandler(Context context) {
mContext = context;
}
public static void registCrashHandler(Context context, String logPath,Class restartActivity, OnCrashListener listener) {
if (mInstance == null) {
synchronized (CrashHandler.class) {
if (mInstance == null) {
mInstance = new CrashHandler(context);
mInstance.setRestartClass(restartActivity);
mInstance.setOnCrashListener(listener);
mInstance.setLogPath(logPath);
Thread.setDefaultUncaughtExceptionHandler(mInstance);//设置自定义的UncaughtExceptionHandler
}
}
}
}
public void setRestartClass(Class restartActivity) {
mRestartClass = restartActivity;
}
public void setLogPath(String path){
mLogPath = path;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
if (mListener != null) {
mListener.onCrashBegin();
}
File logFile = new File(mLogPath);
if(!logFile.getParentFile().exists()){
logFile.getParentFile().mkdirs();
}
//文本的格式可自行调整
FileWriter fw = new FileWriter(logFile, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("\n#####################\n");
bw.write("crashedTime=" + getNowTimeString() + "\n");
HashMap<String, String> deviceInfo = getDeviceInfo();
//保存设备信息
for (HashMap.Entry<String, String> entry : deviceInfo.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
bw.write(key + "=" + value + "\n");
}
//保存堆栈信息
bw.write("\n###message###\n");
bw.write(ex.getMessage() + "\n");
bw.write("\n###StackTrace###\n");
final StackTraceElement[] stack = ex.getStackTrace();
for (StackTraceElement ele : stack) {
bw.write(ele.toString() + "\n");
}
bw.flush();
fw.flush();
bw.close();
fw.close();
//Thread.sleep(100);若回调中某些操作需要一些时间,可以sleep一下
} catch (Exception e) {
e.printStackTrace();
}
restart();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
//收集设备信息
private HashMap<String, String> getDeviceInfo() {
HashMap<String, String> map = new HashMap<>();
try {
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
PackageManager.GET_ACTIVITIES);
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
map.put("versionName", versionName);
map.put("versionCode", versionCode);
map.put("build.version.release", Build.VERSION.RELEASE);
map.put("build.version.sdk", "" + Build.VERSION.SDK_INT);
map.put("build.model", Build.MODEL);
map.put("build.manufacturer", Build.MANUFACTURER);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return map;
}
private String getNowTimeString() {
Calendar calendar = Calendar.getInstance();
String pattern = "yyyy_MM_dd_HH_mm";
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
return sdf.format(calendar.getTime());
}
//重新启动
private boolean restart() {
try {
if (mRestartClass == null) {
return false;
}
Intent intent = new Intent(mContext.getApplicationContext(),
CrashRestartReceiver.class);
intent.putExtra("RESTART_CLASS", mRestartClass);
PendingIntent pI = PendingIntent.getBroadcast(mContext.getApplicationContext(),
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager mgr = (AlarmManager) (mContext.getSystemService(Context.ALARM_SERVICE));
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pI); // 0.1秒钟后重启应用
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public interface OnCrashListener {
void onCrashBegin();
}
public void setOnCrashListener(OnCrashListener listener) {
this.mListener = listener;
}
}
重启应用的BroadcastReceiver
public class CrashRestartReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Class restartClass = (Class) intent.getSerializableExtra("RESTART_CLASS");
Intent newIntent = new Intent(context, restartClass);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
}
}
在Application的onCreate方法中,调用:
CrashHandler.registCrashHandler(Context context, String logPath,Class restartActivity, OnCrashListener listener) 方法
并且静态注册CrashRestartReceiver