对于setRetainInstance()这个方法大多数人还是比较陌生的,之前我也不太理解,只是了解个大概,就是在配置改变时,Fragment不会被重新创建,这里的配置我们就以横竖屏切换为例,这边文章将会带你从源码的角度来分析,基于support-v4-23.1.0,其他版本的原理也是一致的,相信看完之后你会对Fragment销毁时的状态的保存和重建时状态的恢复有一个更加清晰的认识。
先我们来看个简单的例子,Activity代码:
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "SecondActivity";
private SimpleFragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: "+getRequestedOrientation());
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
});
FragmentManager manager = getSupportFragmentManager();
Fragment simple_fragment = manager.findFragmentByTag("simple_fragment");
if (simple_fragment == null) {
fragment = new SimpleFragment();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(fragment,"simple_fragment").commit();
}
Log.d(TAG, "simple_fragment = "+simple_fragment);
}
}
Fragment代码:
public class SimpleFragment extends Fragment {
private static final String TAG = "SimpleFragment";
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach: ");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: ");
setRetainInstance(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: ");
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onViewCreated: ");
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: ");
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "onDetach: ");
}
}
Fragment的onCreate()方法中需要,有一个setRetainInstance(true)方法,这里有个需要注意的点,那就是如果调用setRetainInstance(true),那么onCreate()就只会被调用一次。测试的时候分两种情况,一是注释掉这个方法,二是不注释掉,在这两种情况下运行并进行横竖屏切换,在Activity中查看打印SimpleFragment实例的日志,可以发现,在注释掉setRetainInstance(true)运行时,每次打印的SimpleFragment实例都是不一样的,如果不注释掉setRetainInstance(true)运行时,这就是setRetainInstance(true)的作用。下面我们就去源码中一探究竟。
先来看下setRetainInstance(true)这个方法中具体做了些什么:
public void setRetainInstance(boolean retain) {
if (retain && mParentFragment != null) {
throw new IllegalStateException(
"Can't retain fragements that are nested in other fragments");
}
mRetainInstance = retain;
}
很简单,就是对mRetainInstance 属性进行了赋值,接下来我们就该想到,在Activity销毁时,状态的保存会调用onSaveInstanceState()方法,Fragment的使用,继承的是FragmentActivity,那么我们就去FragmentActivity看看onSaveInstanceState()这个方法做了些什么东西:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
}
可以看到这里就是简单的调用了mFragments.saveAllState()并返回一个Parcelable对象,然后保存到了Bundle中,Activity销毁后,这个Bundle实际是ActivityManagerService给我们保存了,当下次在重新创建时再重新传回给我们,这里我们我们就不去细究了,接下来我们就去看下saveAllState()这个方法里做了些什么,这里先提一点,对于mFragments变量调用的方法最终都会调用FragmentManager中,记住了,后面就不在重复了,所以这里最终调用到的是FragmentManager中的saveAllState():
Parcelable saveAllState() {
// Make sure all pending operations have now been executed to get
// our state update-to-date.
execPendingActions();
if (HONEYCOMB) {
// As of Honeycomb, we save state after pausing. Prior to that
// it is before pausing. With fragments this is an issue, since
// there are many things you may do after pausing but before
// stopping that change the fragment state. For those older
// devices, we will not at this point say that we have saved
// the state, so we will allow them to continue doing fragment
// transactions. This retains the same semantics as Honeycomb,
// though you do have the risk of losing the very most recent state
// if the process is killed... we'll live with that.
mStateSaved = true;
}
if (mActive == null || mActive.size() <= 0) {
return null;
}
// First collect all active fragments.
int N = mActive.size();
FragmentState[] active = new FragmentState[N];
boolean haveFragments = false;
for (int i=0; i<N; i++) {
Fragment f = mActive.get(i);
if (f != null) {
if (f.mIndex < 0) {
throwException(new IllegalStateException(
"Failure saving state: active " + f
+ " has cleared index: " + f.mIndex));
}
haveFragments = true;
FragmentState fs = new FragmentState(f);
active[i] = fs;
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = saveFragmentBasicState(f);
if (f.mTarget != null) {
if (f.mTarget.mIndex < 0) {
throwException(new IllegalStateException(
"Failure saving state: " + f
+ " has target not in fragment manager: " + f.mTarget));
}
if (fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = new Bundle();
}
putFragment(fs.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
if (f.mTargetRequestCode != 0) {
fs.mSavedFragmentState.putInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
f.mTargetRequestCode);
}
}
} else {
fs.mSavedFragmentState = f.mSavedFragmentState;
}
if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
+ fs.mSavedFragmentState);
}
}
if (!haveFragments) {
if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
return null;
}
int[] added = null;
BackStackState[] backStack = null;
// Build list of currently added fragments.
if (mAdded != null) {
N = mAdded.size();
if (N > 0) {
added = new int[N];
for (int i=0; i<N; i++) {
added[i] = mAdded.get(i).mIndex;
if (added[i] < 0) {
throwException(new IllegalStateException(
"Failure saving state: active " + mAdded.get(i)
+ " has cleared index: " + added[i]));
}
if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
+ ": " + mAdded.get(i));
}
}
}
// Now save back stack.
if (mBackStack != null) {
N = mBackStack.size();
if (N > 0) {
backStack = new BackStackState[N];
for (int i=0; i<N; i++) {
backStack[i] = new BackStackState(mBackStack.get(i));
if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
}
}
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
return fms;
}
这个方法中做的主要就是保存Fragment的状态,最后全部封装到FragmentManagerState 中去并返回,这样做的目的就是当下次重新创建Activity的时候可以恢复之前创建的Fragment。
到目前为止,我们还没说到setRetainInstance()设置的mRetainInstance的作用,接下来看看,我们先从源头去跟,这个源头就是ActivityThread的performDestroyActivity()方法,在这个方法中有这样一句代码:
r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
这个r最终是保存在ActivityManagerService中,下次重新创建时会返回给我们,接下来要做的就是去Activity中看看retainNonConfigurationInstances()这个方法是如何实现的:
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
List<Fragment> fragments = mFragments.retainNonConfig();
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
这里有一个onRetainNonConfigurationInstance()方法,这个方法在Activity是空实现,那就去它的子类,也就是FragmentActivity去看看做了些什么逻辑处理:
@Override
public final Object onRetainNonConfigurationInstance() {
if (mStopped) {
doReallyStop(true);
}
Object custom = onRetainCustomNonConfigurationInstance();
List<Fragment> fragments = mFragments.retainNonConfig();
SimpleArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (fragments == null && loaders == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.fragments = fragments;
nci.loaders = loaders;
return nci;
}
这里有个mFragments.retainNonConfig(),这里最终调用到是FragmentManager的retainNonConfig()方法,跟进去看看做了什么:
ArrayList<Fragment> retainNonConfig() {
ArrayList<Fragment> fragments = null;
if (mActive != null) {
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null && f.mRetainInstance) {
if (fragments == null) {
fragments = new ArrayList<Fragment>();
}
fragments.add(f);
f.mRetaining = true;
f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
}
}
}
return fragments;
}
setRetainInstance()的作用,就是在这里体现了,我们这里仔细分析下,mActive这个ArrayList集合,里面存放的是添加到FragmentManager中的Fragment,这里就是在遍历这个集合,然后取出这个集合中的每个对象,如果取出的这个对象不为null,并且f.mRetainInstance为true,就会将这个fragment添加fragments集合中,最后并返回,mRetainInstance这个属性就是通过setRetainInstance()进行设置的,忘记的可以往回看。这里返回的集合最终是会保存在ActivityManagerService中的,前面已经说过,这里在说一次,这也就是说,通过设置setRetainInstance(true),fragment实际是不会被销毁的,下次重新创建的时候会直接传过来,那是怎么传过来的呢?下面接着分析。
这里回到FragmentActivity的onCreate()中:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mFragments.restoreLoaderNonConfig(nc.loaders);
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
mFragments.dispatchCreate();
}
这里要注意两点:
1、getLastNonConfigurationInstance()这个方法,主要是为了之后获取Activity上次销毁时保存的fragment实例;
2、mFragments.restoreAllState()这个方法,主要是恢复上次Activity销毁时fragment的状态;
接下来就去分析这两步:
getLastNonConfigurationInstance()方法:
\\ @return Returns the object previously returned by {@link #onRetainNonConfigurationInstance()}.
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
上面是文档的注释,返回的是onRetainNonConfigurationInstance()中返回的,忘记的话可以往回再看看,现在就来看看mLastNonConfigurationInstances这个属性是何时赋值的,在源码中可以看到赋值这个过程是在attach()方法中,这个方法是ActivityManagerService开启Activity时最先调用的Activity的方法,这里传过来的值也是从ActivityManagerService中从过来的,前面有说到,Activity销毁时,fragment实例以及fragment的状态都是保存到了ActivityManagerService中,正好这里又从attach()方法中传回来了,getLastNonConfigurationInstance()方法就说到这。
mFragments.restoreAllState():
前面又说道,对于mFragments调用的方法,最终调用的方法都是在FragmentManager中,所以这里就是去FragmentManager中看看他的restoreAllState(Parcelable state, List nonConfigList)是如何实现的,这里需要传进来两个参数,一个是是之前保存fragment的状态,二是通过设置setRetainInstance(true)保存起来的fragment实例:
void restoreAllState(Parcelable state, List<Fragment> nonConfig) {
// If there is no saved state at all, then there can not be
// any nonConfig fragments either, so that is that.
if (state == null) return;
FragmentManagerState fms = (FragmentManagerState)state;
if (fms.mActive == null) return;
// 这里是判断是否有fragment实例保存,有保存的话就恢复,避免后面去创建
if (nonConfig != null) {
for (int i=0; i<nonConfig.size(); i++) {
Fragment f = nonConfig.get(i);
if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
FragmentState fs = fms.mActive[f.mIndex];
fs.mInstance = f;
f.mSavedViewState = null;
f.mBackStackNesting = 0;
f.mInLayout = false;
f.mAdded = false;
f.mTarget = null;
if (fs.mSavedFragmentState != null) {
fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mSavedFragmentState = fs.mSavedFragmentState;
}
}
}
// Build the full list of active fragments, instantiating them from
// their saved state.
//对于没有保存实例,只是保存了状态的,那就会在这里去重新创建实例
mActive = new ArrayList<Fragment>(fms.mActive.length);
if (mAvailIndices != null) {
mAvailIndices.clear();
}
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
Fragment f = fs.instantiate(mHost, mParent);
if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
mActive.add(f);
// Now that the fragment is instantiated (or came from being
// retained above), clear mInstance in case we end up re-restoring
// from this FragmentState again.
fs.mInstance = null;
} else {
mActive.add(null);
if (mAvailIndices == null) {
mAvailIndices = new ArrayList<Integer>();
}
if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
mAvailIndices.add(i);
}
}
// Update the target of all retained fragments.
if (nonConfig != null) {
for (int i=0; i<nonConfig.size(); i++) {
Fragment f = nonConfig.get(i);
if (f.mTargetIndex >= 0) {
if (f.mTargetIndex < mActive.size()) {
f.mTarget = mActive.get(f.mTargetIndex);
} else {
Log.w(TAG, "Re-attaching retained fragment " + f
+ " target no longer exists: " + f.mTargetIndex);
f.mTarget = null;
}
}
}
}
// Build the list of currently added fragments.
if (fms.mAdded != null) {
mAdded = new ArrayList<Fragment>(fms.mAdded.length);
for (int i=0; i<fms.mAdded.length; i++) {
Fragment f = mActive.get(fms.mAdded[i]);
if (f == null) {
throwException(new IllegalStateException(
"No instantiated fragment for index #" + fms.mAdded[i]));
}
f.mAdded = true;
if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
if (mAdded.contains(f)) {
throw new IllegalStateException("Already added!");
}
mAdded.add(f);
}
} else {
mAdded = null;
}
// Build the back stack.
if (fms.mBackStack != null) {
mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
for (int i=0; i<fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
if (DEBUG) {
Log.v(TAG, "restoreAllState: back stack #" + i
+ " (index " + bse.mIndex + "): " + bse);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
bse.dump(" ", pw, false);
}
mBackStack.add(bse);
if (bse.mIndex >= 0) {
setBackStackIndex(bse.mIndex, bse);
}
}
} else {
mBackStack = null;
}
}
这里就是在恢复fragment,如果有保存实例的,那就不会重新创建,如果没有保存实例的那就会去重新创建,在拿到这些fragment实例后,再恢复他们之前设置的一些状态,这样,整个流程就到这了。
这样一个流程下来,不仅可以让我们对fragment的销毁和重建的整个流程有个清晰的认识,同时,对于Activity销毁时数据的保存以及恢复同样有个清晰的认识,原理是一样的。
如果其中有不明白,欢迎留言!!!