本文共 14536 字,大约阅读时间需要 48 分钟。
对于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; iFragment.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 0) { backStack = new BackStackState[N]; for (int i=0; i
这个方法中做的主要就是保存Fragment的状态,最后全部封装到FragmentManagerState 中去并返回,这样做的目的就是当下次重新创建Activity的时候可以恢复之前创建的Fragment。
到目前为止,我们还没说到setRetainInstance()设置的mRetainInstance的作用,接下来看看,我们先从源头去跟,这个源头就是ActivityThread的performDestroyActivity()方法,在这个方法中有这样一句代码:r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
这个r最终是保存在ActivityManagerService中,下次重新创建时会返回给我们,接下来要做的就是去Activity中看看retainNonConfigurationInstances()这个方法是如何实现的:
NonConfigurationInstances retainNonConfigurationInstances() { Object activity = onRetainNonConfigurationInstance(); HashMapchildren = onRetainNonConfigurationChildInstances(); List fragments = mFragments.retainNonConfig(); ArrayMap 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(); Listfragments = mFragments.retainNonConfig(); SimpleArrayMap 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()方法,跟进去看看做了什么:
ArrayListretainNonConfig() { ArrayList fragments = null; if (mActive != null) { for (int i=0; i (); } 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, ListnonConfig) { // 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 (fms.mActive.length); if (mAvailIndices != null) { mAvailIndices.clear(); } for (int i=0; i (); } 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 = 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 (fms.mAdded.length); for (int i=0; i (fms.mBackStack.length); for (int i=0; i = 0) { setBackStackIndex(bse.mIndex, bse); } } } else { mBackStack = null; } }
这里就是在恢复fragment,如果有保存实例的,那就不会重新创建,如果没有保存实例的那就会去重新创建,在拿到这些fragment实例后,再恢复他们之前设置的一些状态,这样,整个流程就到这了。
这样一个流程下来,不仅可以让我们对fragment的销毁和重建的整个流程有个清晰的认识,同时,对于Activity销毁时数据的保存以及恢复同样有个清晰的认识,原理是一样的。如果其中有不明白,欢迎留言!!!
转载地址:http://tkhai.baihongyu.com/