Fragment重叠问题
2016-06-28 09:58
232 查看
使用replace来添加Fragment,replace的作用相当于是remove() + add() 组合后的作用。即使用replace会先移除掉当前id为content上的Fragment,这个被移除掉的Fragment就会被销毁掉(如果当前事务),然后通过add再把新的Fragment添加到View上。
(1)使用replace方式,相当于在对应id为content的FrameLayout上只有一层,那就是上面的Fragment1,通过replace这种方式,会把Fragment的生命周期再走一遍,如果我们的Fragment中有获取数据的操作的话,会频繁的去拉取数据;使用replace,Fragment绑定的视图一定会销毁,Fragment实例不一定会销毁,主要看有没有添加到回退栈。
(2)而通过add方式,我们可以在id为content的FrameLayout上添加多层,也即可以通过多次add来添加多个Fragment到FrameLayout上。这个时候,我们就可以配合hide()、show()方法来不断切换不同的Fragment。在我们通过add方式添加了Fragment到FrameLayout 的View上之后,通过hide()、show()来切换Fragment还有一个优势就是,当一个Fragment重新show展示出来的时候,它原来的数据还保留在该Fragment上,也就是说hide并不会销毁Fragment,只是单纯的隐藏了而已。
推荐方式:
因此,推荐使用add、hide、show的方式管理Fragment。但是这种方式一些情况下也会有一个缺陷就是:可能会造成Fragment重叠。
比如底部有四个Tab:tab1,tab2,tab3,tab4,对应的Fragment引用为tab1Fragment,tab2Fragment,tab3Fragment,tab4Fragment。
首先通过add将这四个Fragment添加到FragmentManager后,通过hide和show切换不同TAB都可以处于正常情况。
当我们切换到tab1时,假设tab1上的Fragment为 tab1Fragment变量指向的(即tab1Fragment= new Fragment()),这个时候我们按下HOME键,如果长时间没有回到应用或者内存不足了,系统回收了该引用,此时tab1Fragment= null;但是,tab1的Fragment实例其实还是存在与内存中,只是引用被销毁了。
这个时候,我们切换到tab2,这个步骤中,我们会把tab1的fragment隐藏掉,然后显示tab2,即如下操作:
但是,因为此时 tab1Fragment = null,引用变量为空,hide操作无法实现隐藏功能,但是又由于tab1上的Fragment实例还处于内存中,因此此时会造成tab2与tab1重叠的现象。
再切换到tab1时,因为tab1Fragment = null,此时会再去创建一个新的Fragment,放入到tab1上,导致原来的tab1上的Fragment一直存在与内存中导致重叠,直至它被回收。
造成上述问题的原因还是因为我们无法找到那个实例对象Fragment,因为引用tab1Fragment已经为空了。这个时候,我们在add的时候可以给Fragment绑定一个tag,用它来标识该Fragment,如果引用为空了,再通过tag来找到该Fragment。如下:
使用replace方式,虽然这种方式会避免上述的bug,但也是重复创建了对象。
因为replace方式,对应的FrameLayout只有一 层,而add方式,这个FrameLayout其实有2层。
但是这种方式的缺点是:每次replace会把生命周期全部执行一遍,如果在这些生命周期函数 里拉取数据的话,就会不断重复的加载刷新数据。
那么最合适的处理方式是这样的:
Activity与Fragment易混点归纳
(1)使用replace方式,相当于在对应id为content的FrameLayout上只有一层,那就是上面的Fragment1,通过replace这种方式,会把Fragment的生命周期再走一遍,如果我们的Fragment中有获取数据的操作的话,会频繁的去拉取数据;使用replace,Fragment绑定的视图一定会销毁,Fragment实例不一定会销毁,主要看有没有添加到回退栈。
(2)而通过add方式,我们可以在id为content的FrameLayout上添加多层,也即可以通过多次add来添加多个Fragment到FrameLayout上。这个时候,我们就可以配合hide()、show()方法来不断切换不同的Fragment。在我们通过add方式添加了Fragment到FrameLayout 的View上之后,通过hide()、show()来切换Fragment还有一个优势就是,当一个Fragment重新show展示出来的时候,它原来的数据还保留在该Fragment上,也就是说hide并不会销毁Fragment,只是单纯的隐藏了而已。
推荐方式:
因此,推荐使用add、hide、show的方式管理Fragment。但是这种方式一些情况下也会有一个缺陷就是:可能会造成Fragment重叠。
比如底部有四个Tab:tab1,tab2,tab3,tab4,对应的Fragment引用为tab1Fragment,tab2Fragment,tab3Fragment,tab4Fragment。
首先通过add将这四个Fragment添加到FragmentManager后,通过hide和show切换不同TAB都可以处于正常情况。
当我们切换到tab1时,假设tab1上的Fragment为 tab1Fragment变量指向的(即tab1Fragment= new Fragment()),这个时候我们按下HOME键,如果长时间没有回到应用或者内存不足了,系统回收了该引用,此时tab1Fragment= null;但是,tab1的Fragment实例其实还是存在与内存中,只是引用被销毁了。
这个时候,我们切换到tab2,这个步骤中,我们会把tab1的fragment隐藏掉,然后显示tab2,即如下操作:
tx.hide(tab1Fragment); tx.show(tab2Fragment); tx.commit();
但是,因为此时 tab1Fragment = null,引用变量为空,hide操作无法实现隐藏功能,但是又由于tab1上的Fragment实例还处于内存中,因此此时会造成tab2与tab1重叠的现象。
再切换到tab1时,因为tab1Fragment = null,此时会再去创建一个新的Fragment,放入到tab1上,导致原来的tab1上的Fragment一直存在与内存中导致重叠,直至它被回收。
造成上述问题的原因还是因为我们无法找到那个实例对象Fragment,因为引用tab1Fragment已经为空了。这个时候,我们在add的时候可以给Fragment绑定一个tag,用它来标识该Fragment,如果引用为空了,再通过tag来找到该Fragment。如下:
//在添加Fragment时 FragmentManager fm = getSupportFragmentManager(); FragmentTransaction tx = fm.beginTransaction(); tab1Fragment = new Fragment1(); tx.add(R.id.content, tab1Fragment,"fragment1"); tx.commit(); //在使用时,比如切换到tab2时 if(tab1Fragment != null){ tx.hide(tab1Fragment); tx.show(tab2Fragment); tx.commit(); }else{ tab1Fragment = (Fragment1) fm.findFragmentByTag("fragment1"); tx.hide(tab1Fragment); tx.show(tab2Fragment); tx.commit(); }
使用replace方式,虽然这种方式会避免上述的bug,但也是重复创建了对象。
因为replace方式,对应的FrameLayout只有一 层,而add方式,这个FrameLayout其实有2层。
但是这种方式的缺点是:每次replace会把生命周期全部执行一遍,如果在这些生命周期函数 里拉取数据的话,就会不断重复的加载刷新数据。
那么最合适的处理方式是这样的:
1.在add的时候,加上一个tab参数 transaction.add(R.id.content, IndexFragment,”Tab1″); 2.然后当IndexFragment引用被回收置空的话,先通过 IndexFragment=FragmentManager.findFragmentByTag(“Tab1″); 找到对应的引用,然后继续上面的hide,show;
参考
Fragment销毁时replace和add两个方法的区别Activity与Fragment易混点归纳
相关文章推荐
- CentOS上安装JDK1.7 + Tomcat7
- sql 语句 练习
- MSSQL OPTION语句详解
- 【Objective-C】06-点语法
- redis多实例配置
- 关于更新Android sdk之后出现This Android SDK requires Android Developer Toolkit version 23.0.0 or above的解决方法
- javascript 常用验证函数总结
- Visual Source Safe_VSS复制已有解决方案创建新的解决方案
- SAX解析XML
- 本地环境 XAMPP+phpStorm+XDebug+chrome 配置和断点调试
- linux-wget命令
- iOS--错误集锦--svn status 170004
- 每天邮寄回系统情况的SAR脚本
- sqlserver 2008 r2 直接下载地址,可用迅雷下载
- maven web项目配置1-web.xml
- 代码管理_SVN_TortoiseSVN使用教程
- iOS学习笔记
- 图像搜索引擎 - 原理篇
- maven框架下遇到的问题及解决方法
- JAVA 泛型,集合使用方法