备忘录模式实现与研究 - bei1999/work GitHub Wiki

介绍

保存对象状态,之后可以再次恢复到此状态,类似于日常说的“后悔药”,为了保护状态完整性以及内部实现不向外暴露,也就是说不能被对象从外部访问。

定义

在不破坏封闭的前提下,将该对象之外保存这个状态,需要的时候可以将保存的对象恢复到原来的保存状态

场景模拟

  • android 中Activity 中的状态保存

实现

public class MainActivity09 extends BaseActivity {
    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void initPresenter() {
        //TODO
    }

    @Override
    public void initView() {
        //TODO
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }
}

// AppCompatActivity 中的一段代码
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        getDelegate().onSaveInstanceState(outState);
    }
  /**
     * Save all appropriate fragment state.
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mPendingFragmentActivityResults.size() > 0) {
            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);

            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
            }
            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
        }
    }
//跳转到Activity 中的super调用
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }
    /**
     * This method is called after {@link #onStart} when the activity is
     * being re-initialized from a previously saved state, given here in
     * <var>savedInstanceState</var>.  Most implementations will simply use {@link #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 {@link #onSaveInstanceState}.
     *
     * <p>This method is called between {@link #onStart} and
     * {@link #onPostCreate}.
     *
     * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
     *
     * @see #onCreate
     * @see #onPostCreate
     * @see #onResume
     * @see #onSaveInstanceState
     */
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

分析

onSaveInstanceState方法中,分为三个步骤

  1. 存储窗口的视图数的状态
  2. 存储了fragment 的状态
  3. 通过Activity 的ActivityLifeCallbacks dispatchActivitySaveInstanceState 方式进行了存储状态

onRestoreInstanceState方法则通过把存储的Bundle 交给系统的window 进行了恢复restoreHierarchyState

扩展

onSaveInstanceState 调用的时机 并不是每次activity 退出之前都会调用,当某个activity变得容易被系统销毁时,该activity 的onSaveInstanceState就会执行,常见如下:

  1. 用户按home键
  2. 长按home键,切换其他app
  3. 按电源(关闭屏幕)
  4. 屏幕方向切换
  5. 呼入电话时候 概括是,不是用户主动退出或者跳转七天activity就会触发,即当系统存在“未经你许可”时销毁了我们的activity,则onSaveInstanceState会执行,系统这样做的目的是提供保存用户数据的时机。

总结

备忘录模式是在不破坏封装条件下的对内部状态的存储和还原 优点:提供了一种可恢复的时机 缺点:如果需要的数据大,保存和恢复有一定的内存消耗

⚠️ **GitHub.com Fallback** ⚠️