0. 前言
一般的Android應(yīng)用只是對(duì)Crash進(jìn)行捕捉旭旭。而Sunzxyong大神的Recovery框架,能做到對(duì)Crash進(jìn)行捕捉并自動(dòng)恢復(fù)玉转。大大地提高APP的用戶體驗(yàn)芍耘。
本文意在分析Recovery框架的三個(gè)關(guān)鍵點(diǎn),讓大家了解其實(shí)現(xiàn)原理队寇。
Github地址:https://github.com/Sunzxyong/Recovery
1. 捕獲異常
通過(guò)實(shí)現(xiàn)并注冊(cè)接口 Thread.UncaughtExceptionHandler,處理沒(méi)有被try-catch捕獲的異常章姓。
public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// 處理異常:打印異常信息佳遣,恢復(fù)Activity棧
}
// 在外部調(diào)用,注冊(cè)異常捕捉
public static void register() {
Thread.setDefaultUncaughtExceptionHandler(new MyCrashHandler());
}
}
2. 維護(hù)私有的Activity棧
通過(guò)在Application里調(diào)用registerActivityLifecycleCallbacks()進(jìn)行注冊(cè)凡伊,監(jiān)聽(tīng)Activity的創(chuàng)建和銷毀零渐,自己維護(hù)一個(gè)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進(jìn)棧
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);
}
}
注冊(cè)全局的Activity監(jiān)聽(tīng)
((Application) mContext).registerActivityLifecycleCallbacks(new RecoveryActivityLifecycleCallback());
3. 恢復(fù)Activity棧
崩潰時(shí)系忙,通過(guò)startActivities()來(lái)啟動(dòng)多個(gè)Activity诵盼,從而恢復(fù)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. 存在的問(wèn)題
在多進(jìn)程并共用同一個(gè)任務(wù)棧的APP中,因?yàn)槊總€(gè)進(jìn)程內(nèi)存都是獨(dú)立的银还,無(wú)法把不同進(jìn)程的Activity放到同一個(gè)List里风宁。所以在恢復(fù)Activity任務(wù)棧時(shí)會(huì)出現(xiàn)問(wèn)題。
解決方法:對(duì)Activty棧使用本地文件來(lái)保存蛹疯,實(shí)現(xiàn)跨進(jìn)程共享戒财。