本文基于 AOSP android-8.1.0_r31
Android考慮到App可能存在被低殺的可能,所以它提供一些回調(diào)給APP,讓APP在進(jìn)入后臺(tái)時(shí)被低殺之前,能保存一些當(dāng)前APP的狀態(tài)。這樣,當(dāng)發(fā)生低殺且再次重啟后,App可以根據(jù)之前所保存的狀態(tài)來對APP進(jìn)行恢復(fù)。
一、onSaveInstanceState
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).
盡管API中的介紹是說系統(tǒng)去kill掉一個(gè)Activity而不是整個(gè)Application去回收內(nèi)存, 這種情況,暫時(shí)還不知道系統(tǒng)是怎么去做的,作為一個(gè)問題吧。
另一種情況是按HOME鍵時(shí),將Activity放到了后臺(tái)了,經(jīng)過其它操作后,該進(jìn)程可能會(huì)被低殺。當(dāng)再次回到該進(jìn)程時(shí),會(huì)再次恢復(fù)之前保存的狀態(tài)。
API中的介紹是說當(dāng)一個(gè)Activity被Kill之前會(huì)被調(diào)用來保存一些當(dāng)前Activity的狀態(tài),這樣,當(dāng)用戶再次回到該Activity時(shí),之前保存的狀態(tài)可能會(huì)在onCreate或onRestoreInstanceState中恢復(fù)。
在3.0版本之前,onSaveInstanceState一般發(fā)生在performPauseActivity里,
也就是在onPause ->onSaveInstanceState 之前
在3.0及以后的版本,onSaveInstanceState一般發(fā)生在performStopActivity里,
也就是onPause -> onSaveInstanceState -> onStop
也有可能是發(fā)生在handleRelaunchActivity中。
這里以performStopActivity為例進(jìn)行說明,
1.1 App端保存狀態(tài)并往AMS中發(fā)送
private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
...
StopInfo info = new StopInfo();
performStopActivityInner(r, info, show, true, "handleStopActivity");
...
info.activity = r;
info.state = r.state;
info.persistentState = r.persistentState;
mH.post(info);
}
handleStopActivity完成兩件事,
- 一是調(diào)用onSaveInstanceState,
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState, String reason) {
if (r != null) {
...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
callCallActivityOnSaveInstanceState(r);
}
}
...
}
這里請注意,在調(diào)用 callCallActivityOnSaveInstanceState 時(shí),如果一個(gè)Activity已經(jīng)標(biāo)志了mFinished. 表示該Activity即將會(huì)被destroy掉,此時(shí)是沒有必要去保存當(dāng)前Activity狀態(tài)的。比如按BACK鍵時(shí),此時(shí)會(huì)Destroy Activity, 在這種情況下,是不會(huì)調(diào)用 onSaveInstanceState的.
接著看callCallActivityOnSaveInstanceState, 為Activity生成一個(gè)Bundle類型的state. 然后Activity時(shí)會(huì)將一些狀態(tài)保存到該state中。
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
r.state = new Bundle();
r.state.setAllowFds(false);
if (r.isPersistable()) {
r.persistentState = new PersistableBundle();
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
}
- 二是往AMS中發(fā)送StopInfo
從上一小節(jié)調(diào)用onSaveInstanceState可知,信息是保存在Activity里Bundle類型的state中的,那么這個(gè)state最終是放在哪里保存,它才能被恢復(fù)呢???
肯定不會(huì)是保存在當(dāng)前進(jìn)程,因?yàn)槿绻?dāng)前進(jìn)程被低殺了(low memory killer),進(jìn)程里所有的資源,內(nèi)存都會(huì)被回收掉,結(jié)果就是下次進(jìn)來根本找到不之前的Bundle類型的state了。
所以應(yīng)該是保存在system進(jìn)程中了,因?yàn)樗蠥ctivity的啟動(dòng)都是由system進(jìn)程啟動(dòng)的,所以將state保存到system進(jìn)程是可行的。事實(shí)上就是這么干的,下來來看下是如何實(shí)現(xiàn)的。
info.activity = r;
info.state = r.state;
info.persistentState = r.persistentState;
mH.post(info);
handleStopActivity會(huì)post一個(gè)StopInfo, StopInfo里保存了Activity的state值, 它會(huì)通過Binder將state發(fā)送給AMS, Bundle是一個(gè)Parcable, 所以它是可以跨進(jìn)程傳輸。
private static class StopInfo implements Runnable {
ActivityClientRecord activity;
Bundle state;
...
@Override public void run() {
// Tell activity manager we have been stopped.
try {
ActivityManager.getService().activityStopped(
activity.token, state, persistentState, description);
} catch (RemoteException ex) {
...
}
}
}
1.2 AMS保存進(jìn)程Activity中的狀態(tài)
AMS在收到App的請求后,會(huì)調(diào)用activityStopped來試著保存App端Activity的狀態(tài)。
public final void activityStopped(IBinder token, Bundle icicle,
PersistableBundle persistentState, CharSequence description) {
...
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token); //找到AMS中對應(yīng)的ActivityRecord
if (r != null) {
r.activityStoppedLocked(icicle, persistentState, description);
}
}
...
}
activityStoppedLocked會(huì)將Activity的信息保存到ActivityRecord中的 icicle 中,到此,Activity的狀態(tài)信息就保存完畢。
ActivityRecord.java
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
if (newIcicle != null) {
// If icicle is null, this is happening due to a timeout, so we haven't really saved
// the state.
icicle = newIcicle;
...
}
...
}
二、恢復(fù)state
既然有保存,那么就應(yīng)該有恢復(fù)。
2.1 AMS找到之前已經(jīng)保存state的ActivityRecord
當(dāng)用戶重新回到Activity時(shí),實(shí)際上是觸發(fā)了startActivity動(dòng)作。
AMS.startActivity -> AMS.startActivityAsUser ->
-> ActivityStarter.startActivityMayWait -> ActivityStarter.startActivityLocked
-> ActivityStarter.startActivity
-> ActivityRecord r = new ActivityRecord //生成一個(gè)新的ActivityRecord,注意,此時(shí)的ActivityRecord并非之前的被kill掉的Activity。
-> ActivityStarter.startActivity -> ActivityStarter.startActivityUnchecked
-> ActivityRecord reusedActivity = getReusableIntentActivity();
private ActivityRecord getReusableIntentActivity() {
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
...
} else if (putIntoExistingTask) {
if (mLaunchSingleInstance) {
...
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
...
} else {
intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
}
}
return intentActivity;
}
getReusableIntentActivity的目的就是在系統(tǒng)的ActivityStack中查找是否可以復(fù)用的Activity. 這些其實(shí)就是Android的singleInstance, single task的相關(guān)概念。
要復(fù)用Activity, putIntoExistingTask得為true, 可以看下它為true的條件是什么
要么是singleInstance, 要么是single task, 要么設(shè)置NEW_STASK,但是不能是MULTI_TASK等等,這里并不作太多說明。
接著看 findTaskLocked
ActivityRecord findTaskLocked(ActivityRecord r, int displayId) {
mTmpFindTaskResult.r = null;
mTmpFindTaskResult.matchedByRootAffinity = false;
ActivityRecord affinityMatch = null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
...
stack.findTaskLocked(r, mTmpFindTaskResult);
if (mTmpFindTaskResult.r != null) {
if (!mTmpFindTaskResult.matchedByRootAffinity) {
return mTmpFindTaskResult.r;
} else if (mTmpFindTaskResult.r.getDisplayId() == displayId) {
affinityMatch = mTmpFindTaskResult.r;
}
}
}
}
return affinityMatch;
}
findTaskLocked從所有display中所有的stack中,所有的task中依次查找,是否能復(fù)用Activity, 找到后放到mTmpFindTaskResult.r 中
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
...
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
// Overlays should not be considered as the task's logical top activity.
final ActivityRecord r = task.getTopActivity(false /* includeOverlays */);
...
if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (!isDocument && !taskIsDocument
&& result.r == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
簡化后可以看出,是從stack里的mTaskHistory中去找出TOP的Activity來比較,是否是需要復(fù)用的Activity.
/**
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
*/
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
從mTaskHistory定義可以看出來,mTaskHistory是包含了之前所有acitivity. 前提是這個(gè)activity本身沒有被Destroy, 如果一個(gè)Activity被Destroy了,會(huì)調(diào)用removeActivityFromHistoryLocked將該Activity從History中移去。
2.2 App端啟動(dòng)一個(gè)Activity
啟動(dòng)Activity的流程與正常的流程一樣,AMS通過Binder調(diào)用scheduleLaunchActivity, 并將ActivityRecord里的icicle傳遞給App. icicle里的內(nèi)容就是App上次保存的Bundle的內(nèi)容。
app.thread.scheduleLaunchActivity(... r.icicle ... );
public final void scheduleLaunchActivity(... Bundle state ...) {
...
r.state = state; //保存到state里
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
接著會(huì)調(diào)用performLaunchActivity,開始進(jìn)入Activity的生命周期。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//前面的代碼通過反射獲得Activity實(shí)例
if (activity != null) {
//進(jìn)入onCreate生命周期,注意,此時(shí)r.state是上次Activity保存的狀態(tài)信息。
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
//接著調(diào)用 onRestoreInstanceState
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
//調(diào)用onPoseCreate
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
}
}
...
}
從代碼可以看出來,上次Activity所保存的Bundle信息會(huì)依次傳遞給
onCreate -> onRestoreInstanceState -> onPostCreate
至于需要在哪個(gè)地方進(jìn)行恢復(fù),那就是開發(fā)者的事件了。