ViewPager懒加载的实现,理解setUserVisibleHint,而不只是会用就好

简介: Viewpager默认会缓存临近操作的两个页面,也就是至少会缓存一个页面。

Viewpager默认会缓存临近操作的两个页面,也就是至少会缓存一个页面。但我们有时候的需求是需要当滑动到相应页面后再去更新数据,比如网络请求这种,可能你会说,那直接在onResumel里请求数据不就行了,但是ViewPager预加载机制在你处于前一个页面时,已经加载好了下一个页面。当然你也可以将所有页面全部缓存,但这样所消耗的内存不言而喻,而且如果数据过多,第一次进去的时候的速度不可估量。所以这次我们使用懒加载来实现我们的需求。

Fragment 提供了 setUserVisibleHint 方法检测当前碎片是否处于可见状态,但是需要注意的是,这个方法不可以直接回调,因为它与Fragment的生命周期不是同步的。

setOffscreenPageLimit()  方法,缓存的页面数,默认为1。


下面开始我们的操作:

创建一个基类继承与Fragment,并重写其中的 setUserVisibleHint() 与 onActivityCreated() 方法

public abstract class fragment extends Fragment {
    private boolean isvisible;
    //与碎片关联的活动创建完毕时调用
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isvisible = true;
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        //是否对用户可见
        pan(isVisibleToUser);
    }
    public void pan(boolean visble) {
        if (isvisible && visble) {
            //等同于onResume()方法
            getShow();
        } else if (isvisible && !visble) {
            //等同于onPause()方法
            getHint();
        }
    }
    public abstract void getShow();
    public abstract void getHint();
}

用一个Demo来验证一下:

我们先继承Fragment类打印一下日志,然后再继承我们重写的基类。对比一下效果

public class F1 extends Fragment{
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=View.inflate(getActivity(),R.layout.f1,null);
        Log.e("demo","f1");
        return view;
    }
}
public class F2 extends Fragment{
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=View.inflate(getActivity(),R.layout.f2,null);
        Log.e("demo","f2");
        return view;
    }
}
public class F3 extends Fragment{
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=View.inflate(getActivity(),R.layout.f3,null);
        Log.e("demo","f3");
        return view;
    }
}

适配器

public class ViewPagerAdApter extends FragmentStatePagerAdapter {
    private List<Fragment> list;
    public ViewPagerAdApter(FragmentManager fm, List<Fragment> list) {
        super(fm);
        this.list = list;
    }
    @Override
    public Fragment getItem(int i) {
        return list.get(i);
    }
    @Override
    public int getCount() {
        return list.size();
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {
    private ViewPager viewPager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager=findViewById(R.id.viewpager);
        List<Fragment> list=new ArrayList();
        list.add(new F1());
        list.add(new F2());
        list.add(new F3());
        ViewPagerAdApter adApter=new ViewPagerAdApter(getSupportFragmentManager(),list);
        viewPager.setAdapter(adApter);
    }
}

查看一下Log的打印

20190124103753195.gif可以看到在我们切换到第二个页面时,第三个页面已经被默认加载好了 ,现在我们将子碎片继承自我们的基类,并实现其中的抽象方法。

//另外两个碎片同理
public class F1 extends fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = View.inflate(getActivity(), R.layout.f1, null);
        return view;
    }
    @Override
    public void getShow() {
        Log.e("demo","F1可见");
    }
    @Override
    public void getHint() {
        Log.e("demo","F1不可见");
    }
}

效果如下,可以看到当滑动到第二个页面时,Log处就打出了F1不可见,F2可见。

20190124104912625.gif 现在对一些疑点进行分析:

为什么从第三个页面滑动到第二个页面,打印了两次不可见呢?

这是因为Viewpager的缓存机制,默认缓存了N*2+1个页面,所以当你左右两边都有页面时,也就是当前实际有三个页面被缓存。所以当你一旦滑动到第一个页面,默认缓存是1个,所以会销毁掉第三个页面,这时打印的Log就只有一个不可见了。

为什么第一次进来不执行 F1可见呢?

我们在onActivityCreated处打印Log,然后在 setUserVisibleHint处也打印一句Log,观察结果:

image.png

这是因为setUserVisibleHint 在Fragment开始前已经调用了,即就是Viewapager.setAdapter之后就已经调用,但是当时还没有初始化完成,我们的子碎片还没有缓存好,所以我们在fragment基类里面定义了一个变量,只有当 onActivityCreated  碎片一定与相关的活动创建完毕的时候再更改变量的值为true,避免空指针的问题,所以第一次进来时没有执行到我们的方法。

另外,默认缓存多少页面,setUserVisibleHint就会执行多少次,在这里,setUserVisibleHint会首先先于Fragment生命周期执行,然后因为默认缓存了当前页面和下一个页面,所以如果给 setUserVisibleHint处打印Log,就会发现,先两次false,再true.,然后再是Fragment的生命周期。如下图

image.png

目录
相关文章
|
7月前
|
Android开发
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突(一)
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突
|
7月前
|
Android开发 UED 开发者
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突(二)
两种方法,教你解决 ViewPager 嵌套 ViewPager滑动冲突
|
缓存 Android开发
ViewPager的简单使用
本节带来的是Android 3.0后引入的一个UI控件——ViewPager(视图滑动切换工具),实在想不到如何来称呼这个控件,他的大概功能:通过手势滑动可以完成View的切换,一般是用来做APP的引导页或者实现图片轮播,因为是3.0后引入的,如果想在低版本下使用,就需要引入v4兼容包,我们也可以看到,ViewPager在:android.support.v4.view.ViewPager目录下。下面我们就来学习一下这个控件的基本用法。
159 0
|
缓存
ViewPager的缓存机制和懒加载实现
ViewPager的缓存机制和懒加载实现
|
Android开发
ViewPager源码分析(2):滑动及冲突处理
我的简书同步发布:ViewPager源码分析(2):滑动及冲突处理 转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】 上一篇介绍了ViewPager的onMeasure和onLayout两个方法,这是自定义View最基本的两个函数。但是我们的ViewPager有个需求就是滑动,接下来我们一起去学习ViewPager在滑动方面做了哪些工作,以及ViewPager如何处理与子View之间的滑动冲突。由于ViewPager的子View有Decor View还有普通的子View,而本篇文章讲的主要是普通子View,因此,不再去刻意区
ViewPager源码分析(2):滑动及冲突处理
|
前端开发 开发者
一道面试题:ViewPager中的Framgent如何实现懒加载?
setUserVisiblity已被废弃,推荐使用 setMaxLifecycle 处理 Fragment 在 ViewPager 中的懒加载
356 0
一道面试题:ViewPager中的Framgent如何实现懒加载?
|
Android开发
Android笔记:ViewPager和TabLayout连用时,去除ViewPager预加载
Android笔记:ViewPager和TabLayout连用时,去除ViewPager预加载
172 0
fragment嵌套viewpager不显示
fragment嵌套viewpager不显示
159 0
ViewPager(通过反射修改viewpager切换速度)
(创建于2016/11/17) import java.lang.reflect.Field; import android.content.
1080 0
|
容器 缓存
Android--Fragment 实现懒加载和不重复加载
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/79217223 基类: package fragment; import android.
1475 0