备忘录模式的使用场景

1.需要保存一个对象在某一个时刻的状态或部分状态。

2.如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访其内部状态,通过中间对象可以访问其内部状态。

1.Originator:负责创建一个备忘录,可以记录、恢复自身的内部状态。同时Originator还可以根据需要决定Memento存储自身哪些内部状态。

2.Memento:备忘录角色,用于存储Originator 内部状态,并且可以防止Originator 以外的对象访问Memento。

3.Caretaker:负责存储备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录转递给其他对象。

备忘录模式的简单示例

备忘录类,这是一个无状态、无操作的实体类,只负责用来存储Originator角色的一些数据,防止外部直接访问Originator。package beiwanglu.gome.com.designbeiwanglu;/*** Created by user on 2018/8/3.* 备忘录*/public class Memoto {public int mCheckpoint;public int mLifeValue;public String mWeapon;@Overridepublic String toString() {return "Memoto{" +"mCheckpoint=" + mCheckpoint +", mLifeValue=" + mLifeValue +", mWeapon='" + mWeapon + '\'' +'}';}
}
在该类中可以通过createMemoto函数来创建该用户的备忘录对象,也就是将自身状态保存到一个Memoto对象中。
外部可以通过restore函数将CallOfDuty  对象的状态从备忘录对象中恢复。package beiwanglu.gome.com.designbeiwanglu;import android.util.Log;/*** Created by user on 2018/8/3.*/public class CallOfDuty {public static final String TAG = "zy";private int mCheckpoint = 1;private int mLifeValue = 100;private String mWeapon = "沙漠之鹰";//玩游戏public void play() {Log.v(TAG, "玩游戏:" + String.format("第%d关", mCheckpoint) + "游戏中");mLifeValue -= 10;Log.v(TAG, "进度升级啦");mCheckpoint++;Log.v(TAG, "到达 " + String.format("第%d关", mCheckpoint));}//退出游戏public void quit() {Log.v(TAG, "------------------------");Log.v(TAG, "退出前的游戏属性:" + this.toString());Log.v(TAG, "退出游戏");Log.v(TAG, "-------------------------");}/*** 创建备忘录* @return*/public Memoto createMemoto() {Memoto memoto = new Memoto();memoto.mCheckpoint = mCheckpoint;memoto.mLifeValue = mLifeValue;memoto.mWeapon = mWeapon;return memoto;}//恢复游戏public void restore(Memoto memoto) {this.mCheckpoint = memoto.mCheckpoint;this.mLifeValue = memoto.mLifeValue;this.mWeapon = memoto.mWeapon;Log.v(TAG, "恢复后的游戏属性:" + this.toString());}@Overridepublic String toString() {return "CallOfDuty{" +"mCheckpoint=" + mCheckpoint +", mLifeValue=" + mLifeValue +", mWeapon='" + mWeapon + '\'' +'}';}
}
Caretaker类的职责很简单,就是负责管理Memoto对象,也就是备忘录对象。package beiwanglu.gome.com.designbeiwanglu;/*** Created by user on 2018/8/3.* Caretaker,负责管理 Memoto*/public class Caretaker {Memoto mMemto; //备忘录/*** 存档* @param memoto*/public void archive(Memoto memoto) {this.mMemto = memoto;}/*** 获取存档* @return*/public Memoto getMemoto() {return mMemto;}
}
package beiwanglu.gome.com.designbeiwanglu;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//构建游戏对象CallOfDuty game = new CallOfDuty();//1.打游戏game.play();Caretaker caretaker = new Caretaker();//2.游戏存档caretaker.archive(game.createMemoto());//退出游戏game.quit();//恢复游戏CallOfDuty newGame = new CallOfDuty();newGame.restore(caretaker.getMemoto());}
}

Log分析:

V/zy: 玩游戏:第1关游戏中

V/zy: 进度升级啦

V/zy: 到达 第2关

V/zy: ------------------------

V/zy: 退出前的游戏属性:CallOfDuty{mCheckpoint=2, mLifeValue=90, mWeapon='沙漠之鹰'}

V/zy: 退出游戏

V/zy: -------------------------

V/zy: 恢复后的游戏属性:CallOfDuty{mCheckpoint=2, mLifeValue=90, mWeapon='沙漠之鹰'}

Android源码中备忘录设计模式

在Android开发中,备忘录模式应用的是Activity状态的保存,也就是里面的onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState)。当Activity不是正常方式退出时,且Activity在随后的时间内被系统杀死执勤会调用这两个方法让开发人员可以有机会存储Activity的相关信息,并且在下次返回Activity时恢复这些数据。通过这两个函数,开发人员能够在某一些特殊场景下存储与界面相关的信息,提升用户体验。

onSaveInstanceState和onRestoreInstacneState都是Activity中的函数,我们先来分析下onSaveInstanceState。

public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback, WindowControllerCallback,AutofillManager.AutofillClient {/*** Called to retrieve per-instance state from an activity before being killed* so that the state can be restored in {@link #onCreate} or* {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method* will be passed to both).** <p>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 {@link #onCreate} or {@link #onRestoreInstanceState}.** <p>Do not confuse this method with activity lifecycle callbacks such as* {@link #onPause}, which is always called when an activity is being placed* in the background or on its way to destruction, or {@link #onStop} which* is called before destruction.  One example of when {@link #onPause} and* {@link #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 {@link #onSaveInstanceState}* on B because that particular instance will never be restored, so the* system avoids calling it.  An example when {@link #onPause} is called and* not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:* the system may avoid calling {@link #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.** <p>The default implementation takes care of most of the UI per-instance* state for you by calling {@link android.view.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* {@link #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.** <p>If called, this method will occur before {@link #onStop}.  There are* no guarantees about whether it will occur before or after {@link #onPause}.** @param outState Bundle in which to place your saved state.** @see #onCreate* @see #onRestoreInstanceState* @see #onPause*/protected void onSaveInstanceState(Bundle outState) {//1.存储当前窗口的视图树的状态outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);//2.存储Fragment的状态Parcelable p = mFragments.saveAllState();if (p != null) {outState.putParcelable(FRAGMENTS_TAG, p);}if (mAutoFillResetNeeded) {outState.putBoolean(AUTOFILL_RESET_NEEDED, true);getAutofillManager().onSaveInstanceState(outState);}//3.如果用户还设置了Activity的ActivityLifecycleCallbacks//那么调用这些ActivityLifecycleCallbacks的onSaveInstance进行存储状态getApplication().dispatchActivitySaveInstanceState(this, outState);}
}

上述onSaveInstanceState 函数中,主要分为以下3步:

1.存储窗口的视图树的状态。

2.存储fragment的状态。

3.调用Activity的ActivityLifecycleCallbacks的onSaveInstanceState函数进行状态存储。

我们首先来看第一步,在这一步中将Window对象中的视图树中各个View状态存储到Bundle中,这样一来,当用户重新进入到该Activity时,用户UI的结构、状态才会被重新恢复,以此来保证用户界面的一致性。Window类的具体实现类是PhoneWindow,我们看看PhoneWindow中saveHierarchyState函数的实现。

    @Overridepublic Bundle saveHierarchyState() {Bundle outState = new Bundle();if (mContentParent == null) {return outState;}//通过SparseArray类来存储,这相当于一个key为整型的mapSparseArray<Parcelable> states = new SparseArray<Parcelable>();//调用mContentParent的saveHierarchyState方法,这个mContentParent就是调用Activity的setContentView函数设置的内容视图,它是内容视图的根节点,在这里存储整棵视图树的结构。(ViewGroup mContentParent)mContentParent.saveHierarchyState(states);//将视图树的结构放到outState中outState.putSparseParcelableArray(VIEWS_TAG, states);// Save the focused view ID.//保存当前界面中获取了焦点的Viewfinal View focusedView = mContentParent.findFocus();//持有焦点的VIew必须要有设置id,否则重新进入该界面时不会恢复它的焦点状态(恢复焦点状态)if (focusedView != null && focusedView.getId() != View.NO_ID) {outState.putInt(FOCUSED_ID_TAG, focusedView.getId());}// save the panels//存储整个面板的状态SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();savePanelState(panelStates);if (panelStates.size() > 0) {outState.putSparseParcelableArray(PANELS_TAG, panelStates);}//存储ActionBar的状态if (mDecorContentParent != null) {SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();mDecorContentParent.saveToolbarHierarchyState(actionBarStates);outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);}return outState;}

在saveHierarchyState 函数中,主要是存储了与当前UI、ActionBar相关的View状态,这里用mParentView来分析。这个mParentView就是我们通过Activity的setContentView函数设置的内容视图,它是整个内容视图的根节点,存储它层级中的View状态也就是存储了用户界面的状态。mContentParent是一个ViewGroup对象,但是,saveHierarchyState 并不是在ViewGroup中,而是在ViewGroup的父类View中。

#View/*** Store this view hierarchy's frozen state into the given container.** @param container The SparseArray in which to save the view's state.** @see #restoreHierarchyState(android.util.SparseArray)* @see #dispatchSaveInstanceState(android.util.SparseArray)* @see #onSaveInstanceState()*/public void saveHierarchyState(SparseArray<Parcelable> container) {//又调用了dispatchSaveInstanceState 来存储状态dispatchSaveInstanceState(container);}//真正存储View的状态的函数/*** Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for* this view and its children. May be overridden to modify how freezing happens to a* view's children; for example, some views may want to not store state for their children.** @param container The SparseArray in which to save the view's state.** @see #dispatchRestoreInstanceState(android.util.SparseArray)* @see #saveHierarchyState(android.util.SparseArray)* @see #onSaveInstanceState()*/#Viewprotected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {//1.注意:如果View没有设置id,那么这个View的状态将不会被存储if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;//2.调用onSaveInstanceState     函数  获取自身的状态Parcelable state = onSaveInstanceState();if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {throw new IllegalStateException("Derived class did not call super.onSaveInstanceState()");}if (state != null) {// Log.i("View", "Freezing #" + Integer.toHexString(mID)// + ": " + state);//3.将自身状态放到container中,key为id、value为自身状态container.put(mID, state);}}}
  /*** Hook allowing a view to generate a representation of its internal state* that can later be used to create a new instance with that same state.* This state should only contain information that is not persistent or can* not be reconstructed later. For example, you will never store your* current position on screen because that will be computed again when a* new instance of the view is placed in its view hierarchy.* <p>* Some examples of things you may store here: the current cursor position* in a text view (but usually not the text itself since that is stored in a* content provider or other persistent storage), the currently selected* item in a list view.** @return Returns a Parcelable object containing the view's current dynamic*         state, or null if there is nothing interesting to save.* @see #onRestoreInstanceState(Parcelable)* @see #saveHierarchyState(SparseArray)* @see #dispatchSaveInstanceState(SparseArray)* @see #setSaveEnabled(boolean)*/@CallSuper@Nullable protected Parcelable onSaveInstanceState() {mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;if (mStartActivityRequestWho != null || isAutofilled()|| mAutofillViewId > LAST_APP_AUTOFILL_ID) {BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);if (mStartActivityRequestWho != null) {state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED;}if (isAutofilled()) {state.mSavedData |= BaseSavedState.IS_AUTOFILLED;}if (mAutofillViewId > LAST_APP_AUTOFILL_ID) {state.mSavedData |= BaseSavedState.AUTOFILL_ID;}state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;state.mIsAutofilled = isAutofilled();state.mAutofillViewId = mAutofillViewId;return state;}//View类的默认存储状态为空return BaseSavedState.EMPTY_STATE;}

在View类中的saveHierarchyState 函数调用了dispatchSaveInstanceState 函数来存储自身的状态,而ViewGroup则覆写dispatchSaveInstanceState 函数来存储自身以及子视图的状态。ViewGroup的dispatchSaveInstanceState 函数如下:

#ViewGroup@Overrideprotected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {super.dispatchSaveInstanceState(container);final int count = mChildrenCount;final View[] children = mChildren;for (int i = 0; i < count; i++) {View c = children[i];if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {c.dispatchSaveInstanceState(container);}}}

在VIewGroup的dispatchSaveInstanceState 函数中会调用 super.dispatchSaveInstanceState(container) 函数存储自身的状态,然后遍历所有的子视图,并且调用子视图的dispatchSaveInstanceState 函数来存储它们的状态。如果这个子视图是ViewGroup类型,那么则再次执行这个过程;如果这个子视图是View类型,那么调用的是View的dispatchSaveInstanceState 函数,在View类的dispatchSaveInstanceState 函数的注释1中有一个很重要的地方,就是在View没有设置id时,这个View的状态是不会被存储到Bundle中的,这个id就是我们平时在xml中通过android:id属性来设置的标识View的唯一性的id。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><ImageViewandroid:id="@+id/my_imageView"android:layout_width="64dp"android:layout_height="64dp"android:contentDescription="@string/app_name"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:text="18sp" /></LinearLayout>

在上述的xml中,ImageView的状态会被存储,而TextView因为没有设置id,它的状态将不会被存储。这里有一个重要点,是这个id在一个Activity的布局中必须是唯一的,因为这些View的状态是通过SparseArray来存储的,这相当于一个map,它的key是View的id、value为View的状态。当在一个视图树中含有两个相同的id时,那么必然会出现状态覆盖的情况。

这些被存储的状态通过onSaveInstance函数得到,但在View类中我们看到返回的是一个空状态,这就意味着,当我们需要存储View的状态时,需要覆写onSaveInstanceState方法,将要存储的数据存放到Parcelable对象中,并且将它返回。我们看看textView的实现。

#TextView
@Overridepublic Parcelable onSaveInstanceState() {Parcelable superState = super.onSaveInstanceState();// Save state if we are forced tofinal boolean freezesText = getFreezesText();boolean hasSelection = false;int start = -1;int end = -1;if (mText != null) {start = getSelectionStart();end = getSelectionEnd();if (start >= 0 || end >= 0) {// Or save state if there is a selectionhasSelection = true;}}//存储TextView的start、end以及文本内容if (freezesText || hasSelection) {SavedState ss = new SavedState(superState);if (freezesText) {if (mText instanceof Spanned) {final Spannable sp = new SpannableStringBuilder(mText);if (mEditor != null) {removeMisspelledSpans(sp);sp.removeSpan(mEditor.mSuggestionRangeSpan);}ss.text = sp;} else {ss.text = mText.toString();}}if (hasSelection) {// XXX Should also save the current scroll position!ss.selStart = start;ss.selEnd = end;}if (isFocused() && start >= 0 && end >= 0) {ss.frozenWithFocus = true;}ss.error = getError();if (mEditor != null) {ss.editorState = mEditor.saveInstanceState();}//返回对象状态return ss;}return superState;}

调用了View的onSaveInstanceSate函数之后,就得到了View要存储的数据,此时执行到注释3处,这里以View的id为key,以状态为值存储到container(SparseArray类型)中。

if (state != null) {

// Log.i("View", "Freezing #" + Integer.toHexString(mID)

// + ": " + state);

//3.将自身状态放到container中,key为id、value为自身状态

container.put(mID, state);

}

经过一层一层地遍历之后,整个视图树的状态就被存储起来了。

存储完Window的视图树状态信息之后,便会执行存储Fragment中的状态信息、回退栈等。这个存储Fragment状态信息也是调用它的onSaveInstanceState方法,存储Fragment的View视图树状态,最后就是调用用户设置的ActivityLifecycleCallbacks的onSaveInstanceState方法,让用户能够再做一些额外的处理。至此,整个存储过程就完成了。

final void performStopActivity(IBinder token, boolean saveState, String reason) {//获取ActivityClientRecordActivityClientRecord r = mActivities.get(token);//执行performStopActivityInner,saveState表示是否需要存储状态。performStopActivityInner(r, null, false, saveState, reason);
}#ActivityThread
/*** Core implementation of stopping an activity.  Note this is a little* tricky because the server's meaning of stop is slightly different* than our client -- for the server, stop means to save state and give* it the result when it is done, but the window may still be visible.* For the client, we want to call onStop()/onStart() to indicate when* the activity's UI visibility changes.*/
private void performStopActivityInner(ActivityClientRecord r,StopInfo info, boolean keepShown, boolean saveState, String reason) {if (localLOGV) Slog.v(TAG, "Performing stop of " + r);if (r != null) {if (!keepShown && r.stopped) {if (r.activity.mFinished) {// If we are finishing, we won't call onResume() in certain// cases.  So here we likewise don't want to call onStop()// if the activity isn't resumed.return;}RuntimeException e = new RuntimeException("Performing stop of activity that is already stopped: "+ r.intent.getComponent().toShortString());Slog.e(TAG, e.getMessage(), e);Slog.e(TAG, r.getStateString());}// One must first be paused before stopped...performPauseActivityIfNeeded(r, reason);if (info != null) {try {// First create a thumbnail for the activity...// For now, don't create the thumbnail here; we are// doing that by doing a screen snapshot.info.description = r.activity.onCreateDescription();} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to save state of activity "+ r.intent.getComponent().toShortString()+ ": " + e.toString(), e);}}}// Next have the activity save its current state and managed dialogs...if (!r.activity.mFinished && saveState) {if (r.state == null) {//执行Activity的OnSaveInstanceState()函数callCallActivityOnSaveInstanceState(r);}}if (!keepShown) {try {// Now we are idle.//执行Activity的onStop函数r.activity.performStop(false /*preserveWindow*/);} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to stop activity "+ r.intent.getComponent().toShortString()+ ": " + e.toString(), e);}}r.stopped = true;EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),r.activity.getComponentName().getClassName(), reason);}}
}
#ActivityThreadprivate 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  函数mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);}}

在performStopActivity 函数中通过token从mActivties中获取一个ActivityClientRecord对象,这个对象存储了Activiy的信息,我们的状态信息就包含在其中。获取到这个ActivityClientRecord之后,调用了performStopActivityInner 函数,这个函数的执行步骤如下:

1.判断是否需要存储Activity状态;

2.如果需要存储Activity状态,调用onSaveInstanceState函数;

3.将状态信息存储到ActivityClientRecord 对象的state字段中。

4.调用Activity的onStop方法

在执行onStop函数之前,系统会根据情况来选择是否存储Activity的状态,并且将这些状态存储到mActivities中。这个mActivities维护了一个Activity的信息表,当Activity重新启动时,会从mActivities查询对应的ActivityRecord,如果这个对象中含有状态信息,那么则调用Activity的onRestoreInstanceState函数。

#ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);}ComponentName component = r.intent.getComponent();if (component == null) {component = r.intent.resolveActivity(mInitialApplication.getPackageManager());r.intent.setComponent(component);}if (r.activityInfo.targetActivity != null) {component = new ComponentName(r.activityInfo.packageName,r.activityInfo.targetActivity);}//创建Context,类型是ContextImplContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();//1.构建Activityactivity = 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 {//2.创建一个ApplicationApplication app = r.packageInfo.makeApplication(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());if (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}appContext.setOuterContext(activity);//3.关联appContext、Application对象到Activity中。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 (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}activity.mCalled = false;//4.调用Activity的onCreate方法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.stopped = true;if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}//5.调用Activity的onRestoreInstacneState  恢复状态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);}}if (!r.activity.mFinished) {activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);} else {mInstrumentation.callActivityOnPostCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onPostCreate()");}}}r.paused = true;//6.将Activity的信息记录对象存储到mActivities中mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;
}

在注释5处,系统会判断ActivityClientRecord对象中的state是否为空,如果不为空则说明存储了该Activity的状态,此时就会调用Activity的onSaveInstanceState函数获取Activity的UI状态信息,然后将这些信息传递给Activity的onCreate函数,使得用户可以在onCreate函数中恢复UI上的状态。

在这个过程中,Activity扮演了Caretaker角色,负责存储、恢复UI的状态信息;Activity、Fragment、View、ViewGroup等对象为Originator角色,也就是需要存储状态的对象;Memoto则由Bundle来扮演。Activity在停止之前会根据Activity的退出情景来选择是否需要存储状态,在重新启动该Activity时会判断ActivityClientRecord对象中是否存储了Activity状态,如果含有状态则调用Activity的onRestoreInstanceState函数,从而使得Activity的UI效果与上次保持一致,这样一来,就保证了在非正常退出情况下退出Activity时不会丢失数据的情况,很好地提升了用户体验。

参考《Android源码设计模式》

android设计模式之备忘录模式相关推荐

  1. Android设计模式之——备忘录模式

    一.介绍 备忘录模式是一种行为模式,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态,这有点像我们平时说的"后悔药".备忘录模式实现的方式需要保证被保存的对象状态不能被对 ...

  2. java备忘录模式 类图,Android编程设计模式之备忘录模式详解

    本文实例讲述了Android编程设计模式之备忘录模式.分享给大家供大家参考,具体如下: 一.介绍 备忘录模式是一种行为模式,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态,这有点像我们平时 ...

  3. java备忘录模式应用场景_图解Java设计模式之备忘录模式

    图解Java设计模式之备忘录模式 游戏角色状态恢复问题 游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态. ...

  4. java之备忘录模式,java设计模式之备忘录模式

    java设计模式之备忘录模式 代码无错便是优? 简介: 在不破坏封装性的前提下 , 捕获一个对象的内部状态,并在该对象之外保存这个状态 , 这样以后就可以将该对象恢复到原先保存的状态 . 备忘录模式就 ...

  5. Alamps学习设计模式之备忘录模式(笑话:劫个色OR抢个鸡蛋版)

    //设计模式之备忘录模式(月光宝盒版),只要喊菠萝菠萝蜜,就能返回事件的原点.//至尊宝//爱你一万年 class LoverWords {// 模拟Memento     private Strin ...

  6. 设计模式之备忘录模式 转载

    https://juejin.im/post/59c8eb6951882564c5164c5f 设计模式之备忘录模式 备忘录模式 介绍 是一种行为模式 用于保存对象当前状态,并在之后恢复到此状态(后悔 ...

  7. 设计模式之备忘录模式(Memento)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  8. 设计模式复习-备忘录模式

    #pragma once #include "stdafx.h" #include<string> #include<iostream> using nam ...

  9. 设计模式:备忘录模式(Memento)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

最新文章

  1. stopImmediatePropagation函数和stopPropagation函数的区别
  2. docker挂载本地目录的方法总结:
  3. word2vec模型的理解
  4. Spring Boot基础讲解
  5. (16)css背景属性常用应用场景
  6. linux 字符串截取_第13篇:Linux防火墙的日志基本审计
  7. windows下mysql5.6安装
  8. android 数组排重方法,js数组去重方法集合 - osc_779ncf3o的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. 使用cJSON库解析和构建JSON字符串
  10. SpringCloud实战(一)基于nacos实现订单+视频服务的调用
  11. 新版Idea设置代码提示背景色
  12. Opencv中convertTo函数2
  13. 前端解决浏览器直接打开图片URL,下载问题
  14. Qt5.2.1 + VS2012 环境配置
  15. html展开阅读全文代码,一个简单的html点击展开/关闭代码
  16. 18获得触发事件元素节点的方法
  17. 对话知名视觉艺术设计师走尺:只要用心 人人是插画师
  18. 宏碁传奇Go评测 怎么样
  19. Mac搜不到wifi
  20. SQL Server 数据库之嵌套查询

热门文章

  1. 【金阳光测试】Android自动化测试第一季第零讲--预备知识
  2. docker 安装 zulip
  3. SV -- Array 数组
  4. web漏洞扫描工具AWVS使用
  5. C语言的error: two or more data types in declaration specifiers
  6. Python中三种类型的引号(单引号、双引号、三引号)
  7. vue获取上传图片的名字和路径_vue.js,_vue 上传图片路径不对,vue.js - phpStudy
  8. Maven---本地仓库访问私服配置
  9. 张艺谋成为2008年北京奥运会开闭幕式总导演
  10. 云计算——云计算部署形成及应用