[Framework] Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 的一些笔记

Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 的一些笔记

刚开始学习 Android 的时候,就有了解 ActivityonSaveInstanceState()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 BonSaveInstance() 方法,因为在上面的场景中可以保证 Activity B 肯定不需要恢复,所以系统不会调用。这里又举了一个例子 Activity A 启动了一个 Activity B,但是系统可以保证在 Activity B 的生命周期内 Activity A 是不会被销毁的,这时也不会调用 Activity AonSaveInstantce() 方法(我不知道这是什么情况一定能够确保 Activity AActivity B 的生命周期内一定不会被回收。😂)。

View#onSaveInstanceState() 方法中默认也保存了一些状态,你可以重写它然后保存一些你自己的 View 的一些状态。

假如 onSaveInstanceState() 方法调用了,在 Android 9 之前是在 onStop() 生命周期之前回调,在 Android 9 及其之后的版本是在 onStop() 生命周期之后回调。


以下就不是官方文档了。。。。。。

我自己测试如果通过返回键或者手动调用 finish() 方法是不会回调 onSaveIntanceState() 方法;如果通过 Activity A 启动 Actviity B 是会导致 Activity AonSaveInstanceState() 方法被回调(这应该不是文档中说的那种特殊情况了,哈哈),像屏幕旋转和配置改变也会导致 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 对象,比如 ResumeActivityItemDestroyActivityItem 等等) 的这么一个任务,在应用进程接收这个消息的 binderServer 就是 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() 方法,然后通过 HandlerClientTransaction 发送至主线程处理,这个 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 的成员变量 mTransactionExecutorexecute() 方法来处理,也就是 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 传递过来的 lifecycleItemStopActvitiyItem,然后会调用其 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 参数固定都是 trueshouldSaveState 用来判断是否需要执行 onSaveInstantceState(),其中一个非常关键的参数就是 r.activity.mFinished 参数,如果是 false 就表示要执行,如果是 true 就表示不需要执行,当由 A 启动 B 时,AmFinished 参数就是 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);
    }

这里调用了 ActivitiyThreadreportStop() 方法:

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 传递给了 AMSAMS 最终会把这个 state 存在 ActivityRecord 中,当下次 Activity 重启时,就会把这个上次保存的 state 再传递给应用进程。

onRestoreInstanceState() 调用流程

ActivityonCreate() 流程消息发送和任务处理机制和 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() 方法开始 ActivityonStart() 生命周期,然后会通过 pendingActions#shouldRestoreInstanceState() 方法来判断是否有需要恢复的数据,然后如果有 state 对象就会调用 callActivityOnRestoreInstanceState() 方法,最终会调用 ActivityonRestoreInstanceState() 方法。这个 state 对象和 onCreate() 中的那个都是同一个对象。基本没有区别。只是 onCreate() 会先回调。

总结

Activity 执行 onStop() 生命周期的时候,会判断 Activity.mFinshed,如果为 false 就表示要保存当前状态,然后就会回调 onSaveInstantceState() 方法来保存对象,保存后的对象会通过 binder 传递给 AMSAMS 会把他保存到 ActivityRecord 中,如果由于某些其他原因导致 Activity 被销毁,然后要执行重建时,AMS 会把上次的状态在 onCreate() 的生命周期中传递给新的 Activity,然后新的 Activity 会在它的 onCreate()onRestoreInstantceState() 方法中回调上次的状态。

这里还可以总结 onSaveInstantceState() 的一些特性:

  • 由于保存使用了 binder 去传输数据,所以理论上它的数据量不能超过 1MB - 8KB(参考:Android Binder 工作原理)。

  • 同样是用了 binder,保存的数据必须支持序列化(基础变量,String, 实现了 Parcelable 接口的对象)

  • onSaveInstantceState()onRestoreInstantceState() 并不会成对出现。

  • 数据保存在 AMS 的内存中,理论上就算当前应用进程被杀死了,下次同样可以恢复数据。

相关推荐
liangmou21218 分钟前
解释小部分分WPI函数(由贪吃蛇游戏拓展)
android·游戏·c#
亚瑟-灰太狼1 小时前
memory泄露分析方法(Binder,Window,View篇)
android
l and2 小时前
Git 行尾换行符,导致无法进入游戏
android·git
程序媛小果2 小时前
基于Django+python的Python在线自主评测系统设计与实现
android·python·django
梁同学与Android2 小时前
Android --- 在AIDL进程间通信中,为什么使用RemoteCallbackList 代替 ArrayList?
android
Frank_HarmonyOS5 小时前
【无标题】Android消息机制
android
凯文的内存7 小时前
Android14 OTA升级速度过慢问题解决方案
android·ota·update engine·系统升级·virtual ab
VinRichard7 小时前
Android 常用三方库
android
Aileen_0v08 小时前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
江上清风山间明月11 小时前
Flutter DragTarget拖拽控件详解
android·flutter·ios·拖拽·dragtarget