全部评论(1条)
-
- lxxj201000 2016-07-06 00:00:00
- 1、发生了页面重启(旋转屏幕、内存不足等情况被强杀重启)。2、使用add()方式加载Fragment; 为什么会发生Fragment重叠? 从源码角度分析,为什么发生页面重启后会导致重叠?(在以add方式加载Fragment的时候) 我们知道Activity中有个onSaveInstanceState()方法,该方法在app进入后台、屏幕旋转前、跳转下一个 Activity等情况下会被调用,此时系统帮我们保存一个Bundle类型的数据,我们可以根据自己的需求,手动保存一些例如播放进度等数据,而后如果 发生了页面重启,我们可以在onRestoreInstanceState()或onCreate()里get该数据,从而恢复播放进度等状态。 而产生Fragment重叠的原因就与这个保存状态的机制有关,大致原因就是系统在页面重启前,帮我们保存了Fragment的状态,但是在重启后恢复时,视图的可见状态没帮我们保存,而Fragment默认的是show状态,所以产生了Fragment重叠现象。 分析: 我们先看FragmentActivity的相关源码: public class FragmentActivity extends ... { final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); protected void onCreate(@Nullable Bundle savedInstanceState) { ...省略 if (savedInstanceState != null) { Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); mFragments.restoreAllState(p, nc != null ? nc.fragments : null); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Parcelable p = mFragments.saveAllState(); ...省略 } } 从上面源码可以看出,FragmentActivity确实是帮我们保存了Fragment的状态,并且在页面重启后会帮我们恢复! 其中的mFragments是FragmentController,它是一个Controller,内部通过FragmentHostCallback间接控制FragmentManagerImpl。相关代码如下: public class FragmentController { private final FragmentHostCallback<?> mHost; public Parcelable saveAllState() { return mHost.mFragmentManager.saveAllState(); } public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) { mHost.mFragmentManager.restoreAllState(state, nonConfigList); } } public abstract class FragmentHostCallback<E> extends FragmentContainer { final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl(); } 通过上面代码可以看出FragmentController通过FragmentHostCallback里的FragmentManagerImpl对象来控制恢复工作。 我们接着看FragmentManagerImpl到底做了什么: final class FragmentManagerImpl extends FragmentManager { Parcelable saveAllState() { ...省略 详细保存过程 FragmentManagerState fms = new FragmentManagerState(); fms.mActive = active; fms.mAdded = added; fms.mBackStack = backStack; return fms; } void restoreAllState(Parcelable state, List<Fragment> nonConfig) { // 恢复核心代码 FragmentManagerState fms = (FragmentManagerState)state; FragmentState fs = fms.mActive[i]; if (fs != null) { Fragment f = fs.instantiate(mHost, mParent); } } } 我们通过saveAllState()看到了关键的保存代码,原来是是通过FragmentManagerState来保存Fragment的状态、所处Fragment栈下标、回退栈状态等。 而在restoreAllState()恢复时,通过FragmentManagerState里的FragmentState的instantiate()方法恢复了Fragment(见下面的分析就明白啦) 我们看下FragmentManagerState: final class FragmentManagerState implements Parcelable { FragmentState[] mActive; // Fragment状态 int[] mAdded; // 所处Fragment栈下标 BackStackState[] mBackStack; // 回退栈状态 ... } 我们只看FragmentState,它也实现了Parcelable,保存了Fragment的类名、下标、id、Tag、ContainerId以及Arguments等数据: final class FragmentState implements Parcelable { final String mClassName; final int mIndex; final boolean mFromLayout; final int mFragmentId; final int mContainerId; final String mTag; final boolean mRetainInstance; final boolean mDetached; final Bundle mArguments; ... // 在FragmentManagerImpl的restoreAllState()里被调用 public Fragment instantiate(FragmentHostCallback host, Fragment parent) { ...省略 mInstance = Fragment.instantiate(context, mClassName, mArguments); } } 至此,我们就明白了系统帮我们保存的Fragment其实Z终是以FragmentState形式存在的。 此时我们再思考下为什么在页面重启后会发生Fragment的重叠? 其实答案已经很明显了,根据上面的源码分析,我们会发现FragmentState里没有Hidden状态的字段! 而Hidden状态对应Fragment中的mHidden,该值默认false... public class Fragment ... { boolean mHidden; } 我想你应该明白了,在以add方式加载Fragment的场景下,系统在恢复Fragment时,mHidden=false,即show状态,这 样在页面重启后,Activity内的Fragment都是以show状态显示的,而如果你不进行处理,那么就会发生Fragment重叠现象! 为什么使用add()加载Fragment会导致重叠? 我们知道加载Fragment有2种方式:replace()和add()。使用replace加载Fragment是不会发生重叠现象的,只有通过add方式才有可能发生重叠现象。 我们一般使用add时,会和show(),hide()配合使用,add配合hide是使Fragment的视图改变为GONE状态;而 replace是销毁Fragment 的视图。页面重启时,add的Fragment会全部走生命周期,创建视图;而replace的非栈顶Fragment不会走生命周期,只有Back时, 才会逐一走栈顶Fragment生命周期,创建视图。 结合上面的源码分析,在使用replace加载Fragment时,页面重启后,Fragment视图都还没创建,所以mHidden没有意义,不 会发生重叠现象;而在使用add加载时,视图是存在的并且叠加在一起,页面重启后 mHidden=false,所有的Fragment都会是show状态显示出来(即VISIBLE),从而造成了Fragment重叠!
-
赞(18)
回复(0)
热门问答
- 从源码角度分析,为什么会发生 Fragment 重叠
2016-07-05 09:20:02
363
1
- 从微观经济学角度分析为什么浙江省流动人口大?
2018-11-23 06:15:49
393
0
- 从分子角度分析表面张力
- 从分子角度分析表面张力
2016-09-21 19:14:08
406
1
- 中航油案例, 从内控角度分析?
2014-04-28 03:28:04
351
1
- 从马克思主义哲学角度分析,为什么挤不出牛奶来?
2016-04-07 05:17:34
528
1
- 从生化角度分析为什么不吃早餐对身体不好
2015-01-19 07:29:44
476
2
- 为什么海拔越高,食品包装袋膨胀起来越多?从物理角度分析。
2010-05-04 03:09:10
604
4
- 从马克思主义哲学的角度分析,为什么挤不出牛奶来
2017-04-11 06:50:35
490
1
- 从微观角度分析 臭氧 与氧气化学性质不同
2018-11-23 04:40:15
491
0
- 从生物学的角度分析臭氧层破坏的影响
- 越具体越好
2007-01-13 03:31:43
533
1
- 从切削力与安全角度分析磨床操作者为什么必须站在砂轮侧面
2016-09-28 09:57:34
713
1
- 从流体力学的角度分析自然界中的河流为什么都是弯曲的
2017-07-27 04:47:14
374
1
- 从经济学角度分析,资本主义国家为什么把牛奶倒在海里浪费都不卖
2013-11-03 20:37:20
422
1
- 从营养学角度分析下什么牌子的牛奶好
2017-09-20 22:17:05
309
1
- 从微观角度分析氯化氢气体不显酸性的原因
2014-06-06 10:34:53
512
3
- 为什么光栅会有重叠现象,光栅重叠现象怎样消除
2015-06-30 17:10:09
651
1
- 单向阀为什么会发生异常声音
2017-12-16 12:39:56
550
1
1月突出贡献榜
推荐主页
最新话题
-
- #八一建军节——科技铸盾,仪器护航#
- 如何选择到合适的磷青铜绞线?磷青铜绞线的质量...如何选择到合适的磷青铜绞线?磷青铜绞线的质量解析和如何选择到合适的绞线?磷青铜绞线是一种特殊的铜合金导线,由铜、锡和磷等元素组成,具有很好的机械性能、电气性能和耐腐蚀性。磷青铜绞线基本定义与特性:磷青铜是铜与锡、磷的合金,质地坚硬,可制弹簧。典型成分为铜(90%)、锡(6-9%)及磷(0.03-0.6%)锡元素提升合金的强度和耐腐蚀性,磷则细化晶粒、增强耐磨性铸造性能。耐磨性:表面氧化层使其在特殊环境下耐腐蚀,使用寿命长导电性:保持铜很好导电性能的同时有化电子传输路径非铁磁性:不含铁元素,避免在强磁场环境中产生额外能量损耗弹性:受到外力作用时能迅速恢复原状
- 八一建军节 铁血铸军魂













参与评论
登录后参与评论