源码解析FragmentActivity重启后数据存储问题
2017-06-06 22:10
731 查看
本文主要分析两个问题
1, 自己写Fragment里面的普通成员变量会被“清理”,但是之前设置的arguments还在,调用getArguments()还能拿到数据。
2, FragmentAcitvity由于内存重启后,里面的Fragment是否是重新创建?
第一个问题:getArguments()为什么能拿到数据。
内存重启,会先调用FragmentAcitvity的onSaveInstanceState,保存fragment状态在mFragments.saveAllState()这行。
进入saveAllState()方法,下面代码最后两行,新建了一个FragmentState,用来保存Fragment数据
再看FragmentState的构造函数,最后一行
mArguments= frag.mArguments; 将Fragment的arguments进行了保存,所以回答了第一个问题。
最后所有数据通过FragmentManagerState进行保存
并在 onSaveInstanceState 方法里,将数据存入Bundle
第二个问题:内存重启后,里面的Fragment是否是重新创建?
答案:重新创建。
首先进入FragmentActivity的onCreate,在Bundle里取出onSaveInstanceState中保存的数据,然后进行restoreAllState。
在restoreAllState里,通过FragmentState.instantiate进行创建
进入instantiate方法,下面代码最后一行
进入最后的Fragment.instantiate(activity, mClassName,mArguments);方法通过反射去创建。
小结:内存重启,fragment的部分数据是通过FragmentActivity的onSaveInstanceState进行保存,并在OnCreate里进行恢复。由于mUserVisibleHint并没有在FragmentState里,所以如果不做好处理,会出现布局重叠。
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 ; 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里,所以如果不做好处理,会出现布局重叠。
相关文章推荐
- Viewpager+fragment数据更新问题解析
- MySQL存储数据乱码的问题解析
- Activity Fragment数据传递(对象)引用不变问题
- 关于UEditor插件的使用以及UEditor数据回显问题,数据库存储标签代码前台页面如何解析问题小结
- MySQL存储数据乱码的问题解析
- Android开发-数据存储SharedPreferences工具类、Set<String>保存问题、源码分析
- Activity Fragment数据传递(对象)引用不变问题
- Fragment向activity传值是出现的数据错误回退问题
- ViewPager+Fragment切换时无法更新数据问题解析(源代码分享)
- Android activity和fragment异步传输数据的问题
- Fresco源码解析 - DataSource怎样存储数据
- android activity中使用fragment ,如果activity崩溃重启 那么会导致fragment会被清空掉(是数据清空,但是fragment依然存在)
- 动手改造Ibatis,使其支持文件系统存储数据列 之 源码下载编译和SqlMapConfig解析
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- Viewpager+fragment数据更新问题解析
- Activity结合Fragment生命周期的全面测试;Fragment not attached to Activity问题解析
- Viewpager+fragment数据更新问题解析
- 使用Intent在Activity与Fragment之间传递数据中存在的返回键错乱问题
- Fresco源码解析 - DataSource怎样存储数据