系列
Fragment (一):Fragment使用详解
Fragment (二):Activity 和Fragment 的异常销毁、状态保存和恢复机制
Fragment (三):源码解析Fragment 返回栈原理
不了解Fragment 使用、生命周期、常用API等的可用先简单看下:Fragment使用详解
可能导致Activity的异常销毁的几种情况:
Android系统中,当可能导致Activity的异常销毁时,会触发Activity和它的所有active fragment 的onSaveInstanceState()保存开发者需要保存的Activity /Fragment状态,同时还会自动保存它们各自的View 状态。若Activity被异常销毁,再次回到该Activity时会重建该Activity和它被销毁前的所有active fragment,并恢复被保存的状态。
**注:**fragment 的hide 和show 不会被保存,所有重建的fragment 的状态都是show,除非在fragment的oncreate()中设置setRetianInstance(true),因为该fragment不会随宿主Activity的销毁而销毁,但该fragment 不能加入返回栈,具体参考:Fragment使用详解中没有视图的Fragment的用处。
“前台”fragment:调用了add()但既没有被销毁也尚未被移到返回栈中的fragment 。
FragmentManagerImpl 中有两个重要的Field:
- mAdded:fragment列表,保存所有前台fragment 。
- mActive:fragment列表,保存所有前台fragment 和返回栈中的fragment ,实际上就是active fragment。
状态分两种:
触发Activity /Fragment 状态保存和恢复只有一种情形:异常销毁。
Activity /Fragment 状态的保存
当可能发生异常销毁时会自动调用Activity和所有active fragment 的onSaveInstanceState()。开发者可重写Activity /Fragment 的onSaveInstanceState(),保存Activity /Fragment状态到savedInstanceState() 中(注:不要忘了调用父类方法)。
Activity的onSaveInstanceState()在onStop()之后,onDestroy()之前或之后触发。
Activity 状态的恢复
可以在onCreate(Bundle savedInstanceState)、onRestoreInstanceState(Bundle savedInstanceState)这两个方法中的savedInstanceState 获取保存的Activity 状态。
Activity /Fragment 状态保存适用于保存占用存储空间较小的数据,若有数据占用存储空间较大,比如图片,则需要使用没有UI 的Fragment来保存,具体参考:fragment 状态保存和恢复。
实现View状态的自动保存,需要为每个View 设置id。TextView 还需要设置android:freezeText=”true”。
触发Activity 的View 状态保存和恢复只有一种情形:异常销毁。
触发Fragment 的View 状态保存和恢复的两种情形:
1、异常销毁。
2、事务进出返回栈。
View状态的保存
无论是对Activity还是Fragment中View状态的保存,本质上都是通过调用Activity /Fragment 中顶级View的saveHierarchyState() 从而实现对Activity /Fragment 中View tree的深度遍历并调用每个View 的onSaveInstanceState() 保存View状态。
除了Fragment 的View状态是保存在Fragment 的一个Field 中外,Activity /Fragment 状态和View状态最终都保存在Activity的一个Field 中。(具体看后面源码分析)
1、异常销毁:Activity的onSaveInstanceState() 中会调用:
2、事务进栈:事务通过addToBackStack() 添加到返回栈中会导致所有从前台进入返回栈的Fragment 的顶级View的saveHierarchyState() 被调用。注意:不会触发Activity 和Fragment 的onSaveInstanceState()。
View状态的恢复
无论是对Activity还是Fragment中View状态的保存,本质上都是通过调用Activity /Fragment 中顶级View的restoreHierarchyState() 从而实现对Activity /Fragment 中View tree的深度遍历并调用每个View的onRestoreInstanceState() 恢复View状态。
1、异常销毁:会触发Activity 和所有active fragment 顶级View的restoreHierarchyState() 。
2、事务出栈:事务出栈会触发该事务涉及到的所有从返回栈出栈转为前台的Fragment 的顶级View的restoreHierarchyState()。
从上面两点可知,自定义View要实现自身状态的保存和恢复,需要重写onSaveInstanceState() 和onRestoreInstanceState()。参考:( )
下面主要通过源码介绍系统自动对View状态的保存和恢复,可以不用看。
Activity /Fragment中View tree的深度遍历并保存View状态的过程,即View的saveHierarchyState(SparseArray container)方法的流程:
View:
/**
* Store this view hierarchy's frozen state into the given container.
*/
public void saveHierarchyState(SparseArray container) {
dispatchSaveInstanceState(container);
}
protected void dispatchSaveInstanceState(SparseArray container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();//调用View的onSaveInstanceState()方法保存自身状态。
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
container.put(mID, state);//这是为何View必须设置id才能保存状态的原因。
}
}
}
ViewGroup:
注意:ViewGroup并未重写View的saveHierarchyState()。
@Override
protected void dispatchSaveInstanceState(SparseArray 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);//遍历子View
}
}
}
只有异常销毁才会触发Activity 的View状态保存。
Activity异常销毁时是如何触发View tree 的深度遍历并保存状态的?流程如下:
Activity:
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());//遍历Activity的View tree并自动保存View状态
Parcelable p = mFragments.saveAllState();//FragmentController的方法
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
PhoneWindow:
/** {@inheritDoc} */
@Override
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
SparseArray states = new SparseArray();
mContentParent.saveHierarchyState(states);//View tree根结点
outState.putSparseParcelableArray(VIEWS_TAG, states);
......
return outState;
}
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
1、异常销毁:
Activity异常销毁时是如何触发active fragment 的View tree 的深度遍历并保存状态的?流程如下:
Activity:
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());//遍历Activity的View tree并自动保存View状态
Parcelable p = mFragments.saveAllState();//FragmentController的方法
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
FragmentController:
/**
* Saves the state for all Fragments.
*/
public Parcelable saveAllState() {
return mHost.mFragmentManager.saveAllState();//mFragmentManager是FragmentManagerImpl的对象。
}
FragmentManagerImpl:
Parcelable saveAllState() {
......
// First collect all active fragments.
int N = mActive.size();
FragmentState[] active = new FragmentState[N];
boolean haveFragments = false;
for (int i=0; i//遍历所有active fragment
Fragment f = mActive.get(i);//取出active fragment
if (f != null) {
......
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = saveFragmentBasicState(f);//
......
} else {
fs.mSavedFragmentState = f.mSavedFragmentState;
}
}
}
......
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
return fms;
}
Bundle saveFragmentBasicState(Fragment f) {
Bundle result = null;
if (mStateBundle == null) {
mStateBundle = new Bundle();
}
f.performSaveInstanceState(mStateBundle);//最终触发Fragment的onSaveInstanceState(Bundle outState)
if (!mStateBundle.isEmpty()) {
result = mStateBundle;
mStateBundle = null;
}
if (f.mView != null) {
saveFragmentViewState(f);//系统自动保存Fragment中的View状态
}
......
return result;
}
void saveFragmentViewState(Fragment f) {
if (f.mInnerView == null) {
return;
}
if (mStateArray == null) {
mStateArray = new SparseArray();
} else {
mStateArray.clear();
}
f.mInnerView.saveHierarchyState(mStateArray);//mInnerView就是Fragment的根布局,即View tree的根结点。
if (mStateArray.size() > 0) {
f.mSavedViewState = mStateArray;
mStateArray = null;
}
}
// The real inner view that will save/restore state.
//实际上就是Fragment的布局,也就是Fragment的onCreateView()中返回的View,会在FragmentManager的moveToState()中被初始化。
View mInnerView;
2、事务进栈:
Fragment事务加入返回栈导致时是如何触发active fragment 的View tree 的深度遍历并保存状态的?流程如下:
详细介绍参考:源码解析Fragment 返回栈原理
Activity /Fragment中View tree的深度遍历并恢复View状态的过程,即View的restoreHierarchyState(SparseArray container)方法的流程:
流程:
1、异常销毁
在Fragment 重建过程中调用自身顶级View的restoreHierarchyState() 。
2、事务出栈
详细介绍参考:源码解析Fragment 返回栈原理