美文网首页
ViewPager+Fragments+LazyLoad

ViewPager+Fragments+LazyLoad

作者: knock_knock | 来源:发表于2017-03-06 22:44 被阅读125次

    ViewPager+Fragments可以帮助Android开发者方便地实现多个tab页之间的切换。可是在使用中你有没有遇到过一些不是那么美丽的状况呢?比方说,进入页面的前几秒钟特别卡顿?从别的页面切换回来,竟然重新加载了页面?从网上Copy了LazyLoad代码下来,来回切换了几次崩溃了?WTF!!!ViewPager+Fragments用起来并不复杂,不消十分钟你就可以把它引入项目,但是要想获得好的体验,就要多花一点功夫了。这篇文章,我就记录一下自己在开发过程中使用到的优化方法。

    LazyLoad

    首先我们来复习一下ViewPager的基础知识(使用FragmentAdapter)。ViewPager默认至多预加载2个Fragment(可见页面称为VisibleFragment,可见页面左右各一个InvisibleFragment),至少预加载一个页面(可见页面是第一个,仅在右侧有一个InvisibleFragment)。也就是说,我们第一次进入页面时,ViewPager至少加载了两个Fragment,一个VisibleFragment,一个InvisibleFragment。如果InvisibleFragment有什么耗时操作,就会连累VisibleFragment特别卡顿。

    聪明如你肯定会想,这个问题so easy,调用一下ViewPager.setOffscreenPageLimit(0),禁止ViewPager预加载不就ok了嘛!naive!

    public void setOffscreenPageLimit(int limit) {
          if (limit < DEFAULT_OFFSCREEN_PAGES) {
              Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                      DEFAULT_OFFSCREEN_PAGES);
              limit = DEFAULT_OFFSCREEN_PAGES;
          }
          if (limit != mOffscreenPageLimit) {
              mOffscreenPageLimit = limit;
              populate();
          }
      }
    

    ViewPager.setOffscreenPageLimit(int limit)方法的源码,可以看到预加载页面至少是DEFAULT_OFFSCREEN_PAGES,这个值是1。

    你可能又会想了,<font color="#ff3131">InvisibleFragment页面从不可见转为可见,这个状态肯定能够捕捉到吧,在页面变为可见的时候执行耗时操作不就可以了嘛</font>!对头!!!这个方法就是Fragment.setUserVisibleHint(boolean isVisibleToUser),一旦Fragment可见状态发生变化,这个方法就会被调用。所以我们就可以这样写:

    /**
     * 是否已加载数据
     */
    private boolean mLoaded = false;
    
    /**
     * 一旦页面可见性发生变化,这个方法就会被调用
     * 当页面可见且数据未加载时,加载数据
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && !mLoaded) {
            mLoaded = true;
            loadData();
        }
    }
    

    这个就是所谓的LazyLoad!

    ViewPager中的Fragment

    学到上面的新技能之后你兴冲冲地去实验,编码>>运行>>不错呀!写博客的小哥没骗我!>>纳尼!崩溃了!这个死骗子,肯定拿假的LazyLoad来骗我,看我不骂死他!看官大爷请息怒!我真没骗你,不信咱们接着往下看!

    这个地方的崩溃应该是NullPointerException,提示在View初始化之前即对其进行了操作。看来setUserVisibleHint()方法被调用时,onCreateView()方法还没有被调用。要解决这个问题我们要首先弄清楚Fragment中相关方法被调用的顺序(你可以在自己项目中把方法的调用都打印出来)。

    然后我们发现Fragment中相关方法的调用顺序是这个样子的:
    setUserVisibleHint()>>onCreateView()>>onActivityCreated()。

    setUserVisibleHint()确实是在onCreateView()之前被调用的,这可怎么办呀?表怂呀!这还能难得住你?添加一个全局变量,标识onCreateView()方法是否被调用,如果没有被调用,setUserVisibleHint()不执行加载数据的操作。然后我们还需要在onActivityCreated()里面二次判断是否首次加载。现在代码长这个样子:

    /**
     * onCreateView()是否被调用
     */
    private boolean mOnCreateViewInvoked = false;
    /**
     * 是否已加载数据
     */
    private boolean mLoaded = false;
    
    /**
     * 一旦页面可见性发生变化,这个方法就会被调用
     * 当onCreateView()已经被调用&&页面可见&&数据未加载时,加载数据
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (mOnCreateViewInvoked && isVisibleToUser && !mLoaded) {
            mLoaded = true;
            loadData();
        }
    }
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mOnCreateViewInvoked = true;
        // your code
    }
    
    /**
     * 二次测试是否首次加载
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (getUserVisibleHint() && !mLoaded) {
            mLoaded = true;
            loadData();
        }
    }
    

    你再试试,现在是不是不崩溃了!我跟你讲了,我写的是真的LazyLoad!

    一点小扩展

    刷了一会儿你又发现问题了,从别的页面返回之后咋又重新加载数据了?在tab页中,我们可能并不希望,页面每次可见的时候数据都重新加载一遍,而是只在第一次可见的时候加载。看官大爷您这个需求比较简单,只需要一行代码就可以搞定了。我们只需要在ViewPager初始化的时候添加一行设置ViewPager.setOffscreenPageLimit(sizeOfFragments)。这样ViewPager中所有的Framgment都不会被回收了,陪你到天荒地老!

    接下来写一篇文章介绍一下两个ViewPager嵌套时,Fragment可见性的判断。

    完!

    相关文章

      网友评论

          本文标题:ViewPager+Fragments+LazyLoad

          本文链接:https://www.haomeiwen.com/subject/qahpgttx.html