0. 前言
一般的Android應用只是對Crash進行捕捉。而Sunzxyong大神的Recovery框架,能做到對Crash進行捕捉并自動恢復。大大地提高APP的用戶體驗。
本文意在分析Recovery框架的三個關鍵點,讓大家了解其實現原理。
Github地址:https://github.com/Sunzxyong/Recovery
1. 捕獲異常
通過實現并注冊接口 Thread.UncaughtExceptionHandler,處理沒有被try-catch捕獲的異常。
public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// 處理異常:打印異常信息,恢復Activity棧
}
// 在外部調用,注冊異常捕捉
public static void register() {
Thread.setDefaultUncaughtExceptionHandler(new MyCrashHandler());
}
}
2. 維護私有的Activity棧
通過在Application里調用registerActivityLifecycleCallbacks()進行注冊,監聽Activity的創建和銷毀,自己維護一個Activity的棧。使用要求:API 14+
public class RecoveryActivityLifecycleCallback implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(final Activity activity) {
.... 省略一些判斷 .....
Window window = activity.getWindow();
if (window != null) {
View decorView = window.getDecorView();
if (decorView == null)
return;
decorView.post(new Runnable() {
@Override
public void run() {
// Activity進棧
RecoveryStore.getInstance().putActivity(activity);
Object o = activity.getIntent().clone();
RecoveryStore.getInstance().setIntent((Intent) o);
}
});
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
// Activity出棧
RecoveryStore.getInstance().removeActivity(activity);
}
}
注冊全局的Activity監聽
((Application) mContext).registerActivityLifecycleCallbacks(new RecoveryActivityLifecycleCallback());
3. 恢復Activity棧
崩潰時,通過startActivities()來啟動多個Activity,從而恢復Activity棧
private void recoverActivityStack() {
ArrayList<Intent> intents = getRecoveryIntents();
if (intents != null && !intents.isEmpty()) {
ArrayList<Intent> availableIntents = new ArrayList<>();
for (Intent tmp : intents) {
if (tmp != null && RecoveryUtil.isIntentAvailable(this, tmp)) {
tmp.setExtrasClassLoader(getClassLoader());
availableIntents.add(tmp);
}
}
if (!availableIntents.isEmpty()) {
availableIntents.get(0).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
availableIntents.get(availableIntents.size() - 1).putExtra(RECOVERY_MODE_ACTIVE, true);
startActivities(availableIntents.toArray(new Intent[availableIntents.size()]));
overridePendingTransition(0, 0);
finish();
return;
}
}
restart();
}
4. 存在的問題
在多進程并共用同一個任務棧的APP中,因為每個進程內存都是獨立的,無法把不同進程的Activity放到同一個List里。所以在恢復Activity任務棧時會出現問題。
解決方法:對Activty棧使用本地文件來保存,實現跨進程共享。