Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 的一些笔记
刚开始学习 Android
的时候,就有了解 Activity
中 onSaveInstanceState()
和 onRestoreInstanceState()
这两个方法,简单来说就是 onSaveInstantceState()
用来保存数据,当 Activity
被销毁后但是还需要重新启动的时候,新启动的 Activity
需要在 onRestoreInstanceState()
回调中来获取上次 Activity
保存的数据,然后根据这些数据恢复上次的一些状态。当开发这么多年了,我发现自己和身边的同事都是很少使用到他们,都快忘记了,这次根据看到的一些源码来记录一下他们。
源码阅读基于 Android 9
官方描述
首先看看 Android
官方是怎么介绍 onSaveInstantceState()
方法:
Called to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate or onRestoreInstanceState (the Bundle populated by this method will be passed to both).
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 or onRestoreInstanceState.
Do not confuse this method with activity lifecycle callbacks such as onPause, which is always called when an activity is being placed in the background or on its way to destruction, or onStop which is called before destruction. One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.
The default implementation takes care of most of the UI per-instance state for you by calling View.onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself.
If called, this method will occur after onStop for applications targeting platforms starting with Build.VERSION_CODES.P. For applications targeting earlier platform versions this method will occur before onStop and there are no guarantees about whether it will occur before or after onPause. Params:
outState -- Bundle in which to place your saved state.
See Also:
onCreate, onRestoreInstanceState, onPause
我来描述一下对上面描述的一些理解:首先 onSaveInstanceState()
方法会在 Activity
可能被杀死,然后在未来的某个时间需要恢复的情况下调用。
这里它举了一个例子:假如在 Activity A
页面之上又启动了一个 Activity B
,但是由于系统资源的问题(大部分情况是内存不足)需要回收 Activity A
,这时就需要销毁 Activity A
,在销毁之前会回调 onSaveInstanceState()
方法来保存数据,当 Activity B
退出后就需要恢复 Activity A
,恢复的数据会在新的 Activity A
实例的 onCreate()
方法和 onRestoreInstantceState()
方法中回调。
然后还说到不要和 Activity
的生命周期回调搞混,onSaveInstanceState()
方法并不是和生命周期方法一样每次都会回调。他举了一个例子 Activity A
这时启动了一个 Activity B
,然后 Activity B
主动退出了,这时就不会回调 Activity B
的 onSaveInstance()
方法,因为在上面的场景中可以保证 Activity B
肯定不需要恢复,所以系统不会调用。这里又举了一个例子 Activity A
启动了一个 Activity B
,但是系统可以保证在 Activity B
的生命周期内 Activity A
是不会被销毁的,这时也不会调用 Activity A
的 onSaveInstantce()
方法(我不知道这是什么情况一定能够确保 Activity A
在 Activity B
的生命周期内一定不会被回收。😂)。
在 View#onSaveInstanceState()
方法中默认也保存了一些状态,你可以重写它然后保存一些你自己的 View
的一些状态。
假如 onSaveInstanceState()
方法调用了,在 Android 9
之前是在 onStop()
生命周期之前回调,在 Android 9
及其之后的版本是在 onStop()
生命周期之后回调。
以下就不是官方文档了。。。。。。
我自己测试如果通过返回键或者手动调用 finish()
方法是不会回调 onSaveIntanceState()
方法;如果通过 Activity A
启动 Actviity B
是会导致 Activity A
的 onSaveInstanceState()
方法被回调(这应该不是文档中说的那种特殊情况了,哈哈),像屏幕旋转和配置改变也会导致 onSaveInstanceState()
方法回调。
总之中心思想就一个:onSaveInstanceState()
方法会在系统认为你的 Activity
有可能被回收但是未来又会被恢复的情况下回调。前台的 Activity
肯定不会回调,手动销毁的 Activitiy
也肯定不会回调。
然后再看看 onRestoreInstanceState()
官方文档:
This method is called after onStart when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. Most implementations will simply use onCreate to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState. This method is called between onStart and onPostCreate.
Params:
savedInstanceState -- the data most recently supplied in onSaveInstanceState. See Also:
onCreate, onPostCreate, onResume, onSaveInstanceState
都没什么好说的了,在 onSaveInstanceState()
方法中都说得差不多了,onRestoreInstanceState()
方法会在 onStart()
方法之后回调,绝大部分情况下都可以通过 onCreate()
生命周期回调中拿到上次需要被恢复的 Activity
状态。
onSaveInstanceState() 调用流程
该流程是 Activity A
启动 Activity B
时, Activity A
调用 onStop()
逻辑。
这个方法会在 onStop()
的生命周期的时候调用。 AMS
需要控制 Actvitiy
Stop
的生命周期的时候会通过 binder
向应用进程发送一个 Transaction
, 其中包含 StopActivityItem
(其他的生命周期就是不同的 Item 对象,比如 ResumeActivityItem
和 DestroyActivityItem
等等) 的这么一个任务,在应用进程接收这个消息的 binder
的 Server
就是 ApplicationThread
。我在 Activity#onDestroy()
延迟回调的文章中有提到这个过程:Activity onDestroy 生命周期延迟回调原理
我们直接 ApplicationThread#scheduleTransaction()
这个方法开始看,它是由 AMS
内部的对象通过 binder
跨进程调用的:
Java
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
这里会在当前线程执行 ClientTransaction#preExecute()
方法,然后通过 Handler
将 ClientTransaction
发送至主线程处理,这个 Handler
就是 ActivityThread
中的 H
,也就是后续的处理去了主线程。
我们再看看 Handler
中是如何来处理这个对象的:
Java
// ...
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
// ...
这里会调用 ActivityThread
的成员变量 mTransactionExecutor
的 execute()
方法来处理,也就是 TransactionExecutor#execute()
方法。
我们再来看看 TransactionExecutor#execute()
方法:
Java
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
log("End resolving transaction");
}
我们直接看看 executeLifeState()
方法:
Java
private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
if (lifecycleItem == null) {
// No lifecycle request, return early.
return;
}
log("Resolving lifecycle state: " + lifecycleItem);
final IBinder token = transaction.getActivityToken();
final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
if (r == null) {
// Ignore requests for non-existent client records for now.
return;
}
// Cycle to the state right before the final requested state.
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
我们前面说过 Activity#Stop
的逻辑 AMS
传递过来的 lifecycleItem
是 StopActvitiyItem
,然后会调用其 execute()
方法。
Java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
这个 client
其实就是 ActivityThread
,调用的就是 ActviityThread#handleStopActivity()
方法。
Java
@Override
public void handleStopActivity(IBinder token, boolean show, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
reason);
if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
+ " win=" + r.window);
updateVisibility(r, show);
// Make sure any pending writes are now committed.
if (!r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
stopInfo.setActivity(r);
stopInfo.setState(r.state);
stopInfo.setPersistentState(r.persistentState);
pendingActions.setStopInfo(stopInfo);
mSomeActivitiesChanged = true;
}
这里继续调用 performStopActivityInnner()
,注意 saveState
参数固定都是 true
,要注意这个 pendingActions
它保存了 stopInfo
,其中那个 r.state
就是我们的 onSaveInstanceState()
中保存的数据,后续他会被传输至 AMS
(后续会说)。
我们继续看 performStopActivityInnner()
方法:
Java
private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
boolean saveState, boolean finalStateRequest, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
if (r != null) {
// ...
// One must first be paused before stopped...
performPauseActivityIfNeeded(r, reason);
if (info != null) {
// ...
}
if (!keepShown) {
callActivityOnStop(r, saveState, reason);
}
}
}
首先会通过 performPauseActivityIfNeeded()
方法检查一下是否需要执行 Pause
的生命周期,如果需要就执行,然后继续调用 callActivityOnStop()
方法。
我们继续看 callActivityOnStop()
流程:
php
private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {
// Before P onSaveInstanceState was called before onStop, starting with P it's
// called after. Before Honeycomb state was always saved before onPause.
final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null
&& !r.isPreHoneycomb();
final boolean isPreP = r.isPreP();
if (shouldSaveState && isPreP) {
callActivityOnSaveInstanceState(r);
}
try {
r.activity.performStop(false /*preserveWindow*/, reason);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.setState(ON_STOP);
if (shouldSaveState && !isPreP) {
callActivityOnSaveInstanceState(r);
}
}
哈哈,关键的来了,saveState
参数固定都是 true
,shouldSaveState
用来判断是否需要执行 onSaveInstantceState()
,其中一个非常关键的参数就是 r.activity.mFinished
参数,如果是 false
就表示要执行,如果是 true
就表示不需要执行,当由 A
启动 B
时,A
的 mFinished
参数就是 false
,当 B
手动退出时 mFinished
就是 true
。这也和官方文档描述的一致。
执行 onSaveInstantceState()
回调的方法是 callActivityOnSaveInstanceState()
,执行 onStop()
回调的方法是 performStop()
,这里会判断系统版本,如果是 Android 9
之前的版本,就是在 onStop()
前执行,反之在 onStop()
后执行,这也和文档描述一致。
Java
private void callActivityOnSaveInstanceState(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);
}
}
最后的这个 state
就是我们写入的对象,我们的数据也被保存在了它里面。前面说到它会被保存在 pendingActions
中。
我们继续回到 TransactionExecutor#executeLifecycleState()
方法:
Java
private void executeLifecycleState(ClientTransaction transaction) {
// ...
// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
我们上面讲的大段的 onStop()
生命周期的逻辑都是 StopActivityItem#execute()
方法内处理的,然后还会调用 postExecute()
方法,记住这个 mPendingActions
,就是我们写完了的数据就会被放在里面。
继续看看 StopActivityItem#postExecute()
方法:
Java
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
client.reportStop(pendingActions);
}
这里调用了 ActivitiyThread
的 reportStop()
方法:
Java
@Override
public void reportStop(PendingTransactionActions pendingActions) {
mH.post(pendingActions.getStopInfo());
}
它是直接 post
StopInfo
对象,它是一个 runnable
对象:
Java
@Override
public void run() {
// Tell activity manager we have been stopped.
try {
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity);
// TODO(lifecycler): Use interface callback instead of AMS.
ActivityManager.getService().activityStopped(
mActivity.token, mState, mPersistentState, mDescription);
} catch (RemoteException ex) {
// ...
}
}
在 StopInfo#run()
方法中就直接把我们的 state
通过 binder
传递给了 AMS
。AMS
最终会把这个 state
存在 ActivityRecord
中,当下次 Activity
重启时,就会把这个上次保存的 state
再传递给应用进程。
onRestoreInstanceState() 调用流程
Activity
的 onCreate()
流程消息发送和任务处理机制和 onStop()
基本时类似的,对应处理任务的对象由 StopActivityItem
变为 LaunchActivityItem
,我们也从它的 execute()
方法作为入口函数来看:
Java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
这里创建了一个 ActivityClientRecord
(其中的属性都是从 AMS
传递过来的)对象来表示在应用层 Activity
的各种信息(在 AMS
对应的就是 ActivityRecord
),这里就有一个我们熟悉的对象 mState
,这个对象中就保存了我们上次 Activity
销毁前保存的数据。client
就是 ActivityThread
对象,这里调用了它的 handleLaunchActivity()
方法。
Java
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
if (!ThreadedRenderer.sRendererDisabled) {
GraphicsEnvironment.earlyInitEGL();
}
WindowManagerGlobal.initialize();
final Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
if (!r.activity.mFinished && pendingActions != null) {
pendingActions.setOldState(r.state);
pendingActions.setRestoreInstanceState(true);
pendingActions.setCallOnPostCreate(true);
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
return a;
}
这里很简单,继续调用 performLaunchActivity()
方法。
Java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// ...
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
// ...
if (activity != null) {
// ...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
// ...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
}
r.setState(ON_CREATE);
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
// ...
} catch (Exception e) {
// ...
}
return activity;
}
这里首先通过反射创建 Activity
实例,然后调用 mInstrumentation#callActivityonCreate()
方法,这里就会传递我们上面提到的 state
,也就是上次 Activity
被销毁前保存的状态,然后经过调用最终会到我们熟悉的 onCreate()
回调,里面也包含 state
。
在 onCreate
执行完毕后,紧接着就会执行 onStart()
的生命周期,也就是会调用 ActivityThread#handleStartActivity()
方法。
Java
@Override
public void handleStartActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions) {
final Activity activity = r.activity;
// ...
// Start
activity.performStart("handleStartActivity");
r.setState(ON_START);
// ...
// Restore instance state
if (pendingActions.shouldRestoreInstanceState()) {
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);
}
}
// ...
}
首先通过 performStart()
方法开始 Activity
的 onStart()
生命周期,然后会通过 pendingActions#shouldRestoreInstanceState()
方法来判断是否有需要恢复的数据,然后如果有 state
对象就会调用 callActivityOnRestoreInstanceState()
方法,最终会调用 Activity
的 onRestoreInstanceState()
方法。这个 state
对象和 onCreate()
中的那个都是同一个对象。基本没有区别。只是 onCreate()
会先回调。
总结
在 Activity
执行 onStop()
生命周期的时候,会判断 Activity.mFinshed
,如果为 false
就表示要保存当前状态,然后就会回调 onSaveInstantceState()
方法来保存对象,保存后的对象会通过 binder
传递给 AMS
,AMS
会把他保存到 ActivityRecord
中,如果由于某些其他原因导致 Activity
被销毁,然后要执行重建时,AMS
会把上次的状态在 onCreate()
的生命周期中传递给新的 Activity
,然后新的 Activity
会在它的 onCreate()
和 onRestoreInstantceState()
方法中回调上次的状态。
这里还可以总结 onSaveInstantceState()
的一些特性:
-
由于保存使用了
binder
去传输数据,所以理论上它的数据量不能超过1MB - 8KB
(参考:Android Binder 工作原理)。 -
同样是用了
binder
,保存的数据必须支持序列化(基础变量,String
, 实现了Parcelable
接口的对象) -
onSaveInstantceState()
和onRestoreInstantceState()
并不会成对出现。 -
数据保存在
AMS
的内存中,理论上就算当前应用进程被杀死了,下次同样可以恢复数据。