让ViewGroup中Fragment可见时才加载和不重复加载的方法
来源:互联网 发布:中小学教师网络培训 编辑:程序博客网 时间:2024/06/03 20:01
首先看一下Fragment的“setUserVisibleHint()”和“getUserVisibleHint()”方法,下面是个测试例子(1):
Fragment——F3的部分代码:
……@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) { Log.i("F3", "setUserVisibleHint "+isVisibleToUser); super.setUserVisibleHint(isVisibleToUser);}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) { Log.i("F3", "onCreate"); super.onCreate(savedInstanceState);}@Overridepublic void onDestroy() { Log.i("F3", "onDestroy"); super.onDestroy();}……
假设现在ViewGroup有三个相邻的Fragment分别为F1、F2、F3(主要代码如上),只在F3的相应方法中加上打印Log的语句,测试结果:
首先进入ViewGroup的界面,我们看到的当然是F1,同时也实例化了F2,F3还没实例化。
点击进入F2,预加载F3,打出Log:“setUserVisibleHint false”和“onCreate”
点击F3,打印:“setUserVisibleHint true”
点击F2:“setUserVisibleHint false”
点击F1:“onDestory”
点击F3:“setUserVisibleHint false”和“setUserVisibleHint true”
点击F1:“setUserVisibleHint false”和“onDestory”
总结:Fragment的API介绍,getUserVisibleHint()返回的变量,是App提供的代表此Fragment当前对于用户是否可见的一个布尔值;
而例子也证明了在实例化Fragment对象时,setUserVisibleHint()方法会在onCreate()前面被调用,在我们的认识中Fragment的生命周期都是从onCreate()方法开始的,而父容器或者说是上一级的上下文对象却在Fragment的生命周期“开始之前”就将它的isVisibleToUser值设置好了,因此,我们可以在onCreate()方法或者之后的onCreateView()、onStart()等方法的里面,根据需要去调用getUserVisibleHint()方法判断Fragment可见性,再根据需要是否加载数据。
注意:setUserVisibleHint()方法是在onCreate()方法、甚至是onAttach()方法之前调用的,所以它里面不能有任何对Context上下文对象的调用!
下面是自己完成的一个,只在界面第一次可见时加载数据,的Fragment例子(2):
public class MessageFragment extends Fragment { private ListView msgLv; private ServiceAdapter msgAdapter; /** * 是否在onStart()方法中发出网络请求,默认在onStart()中 */ private boolean onStartGetNetData = true; /** * 是否已经发出网络请求 */ private boolean hasGotNetData = false; @Override public void setUserVisibleHint(boolean isVisibleToUser) { if(isVisibleToUser && !onStartGetNetData && !hasGotNetData){ //界面可见、还未请求数据并且不是由onStart()请求数据时执行 if(/*判断网络*/){ getNetWorkData();//请求网络数据的方法 hasGotNetData = true; }else{ //用Toast提示没有连接网络 } } super.setUserVisibleHint(isVisibleToUser); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_msg_service, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); msgLv = (ListView) view.findViewById(R.id.msg_lv); msgAdapter = new ServiceAdapter(getActivity()); msgLv.setAdapter(msgAdapter); } @Override public void onStart() { if(getUserVisibleHint() && onStartGetNetData && !hasGotNetData){ //界面可见并从未请求过数据时加载数据 if(/*判断网络的方法*/){ getNetWorkData();//请求网络数据的方法 hasGotNetData = true; }else{ //Toast提示没有连接网络 } }else if(onStartGetNetData){ onStartGetNetData = false;//界面不可见并且是由onStart()加载数据时置为false,委托给setUserVisibleHint()去请求数据 } super.onStart(); } @Override public void onDestroy() { hasGotNetData = false; onStartGetNetData = true;//Fragment的状态会被所属的Activity保存,但不知能保存多久,保险起见变量设为初值 super.onDestroy(); }}
下面说说为什么要这样写:
首先看看ViewGroup滑动时,Fragment的一些周期函数调用顺序(借用上面三个Fragment的例子):
从第一个Fragment滑到第三个、创建对象时:[ setInitialSavedState(SavedState state) 第二次创建Fragment时才会调用 ] -->
setUserVisibleHint() --> onAttach() --> onCreate() --> onCreateView() -->onViewCreated()
--> onViewStateRestored() --> onStart() --> onResume()
从第三个Fragment滑到第一个、对象销毁时:[ setUserVisibleHint() 先跳到ViewPager其它Fragment时才会有,如果直接按Home键时不会被调用 ] -->
onSaveInstanceState() --> onPause() --> onStop() --> onDestroyView() --> onDetach()
结合测试例子(1)分析:
如果我们从F1直接点击显示F3,setUserVisibleHint()方法会被连续调用两次,第一次为不可见,第二次为可见,随后就调用了onCreate()和onStart()等方法。这种情况下好像在setUserVisibleHint()和onStart()方法里都可以进行加载网络,然而没有这么简单。前者:在setUserVisibleHint()方法里不能有任何对Context的引用,因为它还没有调用onAttach()方法,也就是说这里不能通过上下文对象的getSystemService方法获取系统服务、不能得到是否连网;而且界面元素都未初始化,不能设置数据,还可能遇到空指针异常。后者:在onStart()方法里去请求网络的话,当你用Home退出后再进入应用,它又会被调用,也就会再次加载网络。
如果先从F1滑到F2,F3的onCreate()方法已经被调用,也就是onStart()也会被调用而这时界面还不可见也就不会加载网络,等我们再从F2跳到F3时,onStart()方法已经不会被调用,那就没数据了?!
所以现在的需求是:从F1直接跳到F3界面时,由onStart()方法加载网络;从F1滑到F2再滑到F3时,由setUserVisibleHint()方法加载网络。
因此本人添加了onStartGetNetData变量来判断是否由onStart()方法调用网络请求的方法,再添加一个hasGotNetData变量来判断是否已经获取过一次数据。
现在数据只加载一次了,至于怎么刷新,自己再加上一个下拉刷新就OK了。方法简单,语言简陋,如有更好的方法还请赐教。
最后提一下:ViewPager.setOffscreenPageLimit(int number)方法是设置所看到的View周围有多少个View的状态会被保存着,也就是说当我们见到的第一个Fragment被实例化时,它左边和右边的number个Fragment也会被实例化。这个方法虽然能帮我们更简单的实现数据只加载一次,但是如果ViewPager里面的View太多或者其布局太复杂,刚实例化时会消耗大量内存和时间,使用时请谨慎!
2 0
- 让ViewGroup中Fragment可见时才加载和不重复加载的方法
- fragment可见和不可见的方法
- fragment可见和不可见的方法
- 相见恨晚的函数:setUserVisibleHint()实现 fragment 对用户可见时才加载资源(延迟加载)。
- Activity,Fragment的基类封装,简化findViewById,Fragment懒加载和不重复加载等
- 笔记:fragment重复加载和fragment在viewpage中预加载的问题
- 如何让ViewPager+Fragment来回切换时数据不重复加载
- 如何让ViewPager+Fragment来回切换时数据不重复加载
- android中在切换fragment时,怎样做到无需重复加载数据的方法。
- 让浏览器不加载缓存CSS和JS的方法
- fragment懒(可见时)加载
- Fragment懒加载,当页面可见时加载数据
- Fragment + ViewPager + Fragment 中界面不显示、预加载和网络请求的问题
- 如何判断当前的Fragment是否可见?Fragment的可见与不可见的判断方法。
- Fragment 防止重复加载
- Android让Fragment加载到Activity中
- Android让Fragment加载到Activity中
- Android让Fragment加载到Activity中
- 面试经验(妙计旅行:C++算法工程师)
- 单极性PWM和双极性PWM
- 从一到无穷大
- BLE协议架构概述(1)
- maven环境快速搭建
- 让ViewGroup中Fragment可见时才加载和不重复加载的方法
- 矩阵连乘问题的算法分析
- hibernate实现多表联合查询
- Mac系统下,Appium的安装及环境的搭建
- 概率论与数理统计习题: 某县城有1万辆自行车,其牌照号码从00001到10000,求在该县城偶遇一辆自行车的牌照号码中有数字8的概率.
- 抽象工厂模式
- 乐观锁和悲观锁
- swift gcd 延时调用封装
- key_len计算规则