zoukankan      html  css  js  c++  java
  • 防止ViewPager和Fragment结合使用时候的数据预加载

    不知道你们使用ViewPager和Fragment结合的时候发现一个问题没,如果你的每个Fragment都需要请求网络数据,并且你在请求网络数据的时候会加入进度对话框的加载显示效果,当你显示第一个Fragment的时候,进度对话框并不是在你这个Fragment数据加载完成之后就停止显示了,它会等待ViewPager预加载的Fragment数据也加载完成的时候才会停止显示,即你加载第一个Fragment数据时,进度对话框的显示实际上是两个或者三个的层叠显示。

    反正最近我是遇到这种情况了,下面说说我怎么解决的.

    ViewPager和Fragment结合使用的时候,有两种适配器可以使用,一个是FragmentStatePagerAdapter,一个是FragmentPagerAdapter。前者在内存中最多会保留三个Fragment实例,也就是说当有Fragment切换的时候,Fragment生命周期会走onDestroyView()-->onDestroy()方法,然后创建会走onCreate()-->onCreateView()方法。但是对于后者,内存中会保留所有创建后的Fragment,也就是说当Fragment切换的时候,生命周期会走onDestroyView()和onCreateView()方法,但是不会走onDestroy()和onCreate()方法。不管是哪一种PagerAdapter,ViewPager都存在预加载Fragment的效果,为了让数据只有在Fragment显示给用户的时候才去加载,我们做了如下几件事情:

    1.首先,在Fragment里面有一个方法

    public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);    }

    需要注意的是这个方法会在Fragment的onCreate()方法调用之前就调用,这里我们在里面作如下修改

    public void setUserVisibleHint(boolean isVisibleToUser) {        if (isVisibleToUser && isVisible()){            initData();        }        super.setUserVisibleHint(isVisibleToUser);    }

    initData()是加载数据的方法,不用管它。这里isVisibleToUser,如果Fragment是显示给用户的,那么这个值是true,isVisible()方法可以判断Fragment的视图是否创建好,对于第一个显示的Fragment,因为isVisibleToUSer是true,但是isVisible()是false,那么在显示第一个Fragment的时候是空白的。但是对于其它的Fragment,因为存在ViewPager的预加载,当显示到Fragment的时候,isVisible()是true,而不是false。所以会在这个方法里面进行加载数据的操作。

    2.然后,我们来解决第一个Fragment显示空白的问题,我是在onCreateView()方法里面进行数据的加载操作。然后,我在这个方法里面进行如下的修改

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        //...        if (getUserVisibleHint()){            initData();        }        return inflater.inflate(R.layout.fragment_blank, container, false);    }

    这里getUserVisibleHint()方法可以判断当前Fragment是否是显示给用户的,对于第一个Fragment,因为不会在setUserVisibleHint()方法里面进行数据加载操作,当走到onCreateView()方法后,会在这里判断,由于getUserVisibleHint()是true,所以会进行数据的加载。然后对于其它的Fragment来说,因为存在预加载的效果,当先走setUserVisibleHint()方法时,由于isVisibleToUser是false,所以不会进行数据的加载,而走完这个方法到达onCreateView()方法时,getUserVisibleHint()返回的是false,所以也不会进行数据的加载,只有当切换到这个Fragment的时候,会去回调setUserVisibleHint()方法,在这个方法里面进行了数据的加载操作。

    以上就解决了ViewPager和Fragment结合使用的时候数据的预加载。

    3.其实,我觉得上面的做法并不是完美,因为你会发现每次切换到Fragment的时候都会重新加载数据,这样是非常耗流量的。于是乎,我就想了一个办法,在Fragment里面添加了一个long的变量,用来记录Fragment刷新的时间

    private long refreshTime  = 0;

    然后修改setUserVisibleHint()方法,如下所示

    public void setUserVisibleHint(boolean isVisibleToUser) {        if (isVisibleToUser && isVisible()){            if (refreshTime == 0 ||(refreshTime != 0 && (System.currentTimeMillis()-refreshTime) > 30 * 60 * 1000)) {                initData();            }        }        super.setUserVisibleHint(isVisibleToUser);    }

    即如果这个Fragment的View视图没有被销毁的时候,只有当数据的时效性超过30min后再次切换到这个Fragment才会进行数据的加载。

    4.在每次进行数据加载操作的时候对这个时间刷新,在每次View视图被重新创建的时候将时间置为0,如下所示

    private void initData(){    refreshTime=System.currentTimeMillis();}
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        refreshTime = 0;        //.......    }

    好了,以上是关于我如何解决ViewPager和Fragment结合使用时候的数据预加载问题。其实我们还可以进行优化,对每个Fragment获取到的网络数据(一般是json)进行缓存,当每次切换的时候,先去加载本地的json数据进行展示,再去判断当前时间和这个json被缓存的时间是否超过一定的值,如果超过,再进行网络请求刷新数据。我觉得这样会更好。谢谢~晚安了,各位!

  • 相关阅读:
    Linux设备驱动第六篇:高级字符驱动操作之iotcl
    Stack的三种含义
    用vs2013+velt-0.1.4进行嵌入式开发 进行海思平台 UBOOT 开发
    学会思考技术背后的那些思想和本质
    Rails 4.0.0 开发环境一切正常,到生成环境发现 无法找到 css 和 js
    一加手机,迟到的惊喜
    附近的人计算方法-----使用mysql脚本计算方法
    如何将Superset嵌入后台系统之实践
    这里是纯干货!2018年深度学习的10个发展预测
    这里是纯干货!2018年深度学习的10个发展预测
  • 原文地址:https://www.cnblogs.com/wangfeng520/p/5807465.html
Copyright © 2011-2022 走看看