源码解析FragmentActivity重启后数据存储问题

xiaoxiao2021-02-28  127

本文主要分析两个问题

1, 自己写Fragment里面的普通成员变量会被“清理”,但是之前设置的arguments还在,调用getArguments()还能拿到数据。

2, FragmentAcitvity由于内存重启后,里面的Fragment是否是重新创建?

 

第一个问题:getArguments()为什么能拿到数据。

内存重启,会先调用FragmentAcitvity的onSaveInstanceState,保存fragment状态在mFragments.saveAllState()这行。

@Override protected void onSaveInstanceState(Bundle outState) {     super.onSaveInstanceState(outState);     Parcelable p = mFragments.saveAllState();     if (p != null) {         outState.putParcelable(FRAGMENTS_TAG, p);     } }

 

进入saveAllState()方法,下面代码最后两行,新建了一个FragmentState,用来保存Fragment数据

Parcelable saveAllState() {     // 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;

 

再看FragmentState的构造函数,最后一行

public FragmentState(Fragment frag) {     mClassName = frag.getClass().getName();     mIndex = frag.mIndex;     mFromLayout = frag.mFromLayout;     mFragmentId = frag.mFragmentId;     mContainerId = frag.mContainerId;     mTag = frag.mTag;     mRetainInstance = frag.mRetainInstance;     mDetached = frag.mDetached;     mArguments = frag.mArguments; }

mArguments= frag.mArguments; 将Fragment的arguments进行了保存,所以回答了第一个问题。

最后所有数据通过FragmentManagerState进行保存

FragmentManagerState fms = new FragmentManagerState(); fms.mActive = active; fms.mAdded = added; fms.mBackStack = backStack;

并在 onSaveInstanceState 方法里,将数据存入Bundle

@Override protected void onSaveInstanceState(Bundle outState) {     super.onSaveInstanceState(outState);     Parcelable p = mFragments.saveAllState();     if (p != null) {         outState.putParcelable(FRAGMENTS_TAG, p);     } }

第二个问题:内存重启后,里面的Fragment是否是重新创建? 

答案:重新创建。

首先进入FragmentActivity的onCreate,在Bundle里取出onSaveInstanceState中保存的数据,然后进行restoreAllState。

@Override protected void onCreate(Bundle savedInstanceState) {     …………     if (savedInstanceState != null) {         Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);         mFragments.restoreAllState(p, nc != null ? nc.fragments : null);     }     mFragments.dispatchCreate(); }

 

在restoreAllState里,通过FragmentState.instantiate进行创建

for (int i=0; i<fms.mActive.length; i++) {     FragmentState fs = fms.mActive[i];     if (fs != null) {         Fragment f = fs.instantiate(mActivity, 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);     } } 

进入instantiate方法,下面代码最后一行

public Fragment instantiate(FragmentActivity activity, Fragment parent) {     if (mInstance != null) {         return mInstance;     }         if (mArguments != null) {         mArguments.setClassLoader(activity.getClassLoader());     }         mInstance = Fragment.instantiate(activity, mClassName, mArguments);

进入最后的Fragment.instantiate(activity, mClassName,mArguments);方法通过反射去创建。

public static Fragment instantiate(Context context, String fname, Bundle args) {     try {         Class<?> clazz = sClassMap.get(fname);         if (clazz == null) {             // Class not found in the cache, see if it's real, and try to add it             clazz = context.getClassLoader().loadClass(fname);             sClassMap.put(fname, clazz);         }         Fragment f = (Fragment)clazz.newInstance();         if (args != null) {             args.setClassLoader(f.getClass().getClassLoader());             f.mArguments = args;         }         return f;

 

小结:内存重启,fragment的部分数据是通过FragmentActivity的onSaveInstanceState进行保存,并在OnCreate里进行恢复。由于mUserVisibleHint并没有在FragmentState里,所以如果不做好处理,会出现布局重叠。

转载请注明原文地址: https://www.6miu.com/read-27122.html

最新回复(0)