备忘录模式的使用场景
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;
@Override
public 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());
}
@Override
public 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 {
@Override
protected 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 ContextThemeWrapper
implements 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函数的实现。
@Override
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
//通过SparseArray类来存储,这相当于一个key为整型的map
SparseArray<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.
//保存当前界面中获取了焦点的View
final 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()
*/
#View
protected 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
@Override
protected 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">
<ImageView
android:id="@+id/my_imageView"
android:layout_width="64dp"
android:layout_height="64dp"
android:contentDescription="@string/app_name"/>
<TextView
android: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
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
// Save state if we are forced to
final 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 selection
hasSelection = 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) {
//获取ActivityClientRecord
ActivityClientRecord 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);
}
}
}
#ActivityThread
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 函数
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,类型是ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
//1.构建Activity
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 {
//2.创建一个Application
Application 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源码设计模式》