仪器网(yiqi.com)欢迎您!

| 注册2 登录
网站首页-资讯-专题- 微头条-话题-产品- 品牌库-搜索-供应商- 展会-招标-采购- 社区-知识-技术-资料库-方案-产品库- 视频

问答社区

从源码角度分析,为什么会发生 Fragment 重叠

caro90 2016-07-05 09:20:02 363  浏览
  •  

参与评论

全部评论(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月突出贡献榜

推荐主页

最新话题