美文网首页
新方式 - 实现 viewPager fragment 延迟加载

新方式 - 实现 viewPager fragment 延迟加载

作者: zhaoyubetter | 来源:发表于2017-07-04 12:03 被阅读132次

    为什么需要延迟加载

    在Viewpager中,默认加载下一页的数据,比如在Page1页面时,会加载下一页的Page2一般我们结合Viewpager、fragment、tablayout一起联合使用;
    fragment加载数据时,我们习惯从 onViewCreated() 回调方法中,进行数据的加载(比如:请求网络),如果在Page1时,这个时候 Page2 的 onViewCreated() 会执行,如果用户不进行 Page2 的访问,会造成一定的资源浪费,用户体验不是很好;
    所以,最好的方式是用户滑动具体某个页面时(比如Page3),才去加载(Page3)的页面数据;

    传统的解决方案

    原理:

    利用 Fragment 的几个回调方法,setUserVisibleHint , onResume 并结合全局变量来进行判断;
    具体可参考:

    http://www.cnblogs.com/tiantianbyconan/p/4303910.html

    隐含的问题:

    这样做造成基类,会有大量判断,而且,需求一旦修改要求(如:实时加载数据),造成改动过大;

    新方案 -> 从PagerAdapter入手

    通过对FragmentPagerAdapter 源码进行分析,发现方法setPrimaryItem
    具体代码如下:

        public void setPrimaryItem(ViewGroup container, int position, Object    object) {
            Fragment fragment = (Fragment)object;
            if (fragment != mCurrentPrimaryItem) {
                if (mCurrentPrimaryItem != null) {
                    mCurrentPrimaryItem.setMenuVisibility(false);
                    mCurrentPrimaryItem.setUserVisibleHint(false);
                }
                if (fragment != null) {
                    fragment.setMenuVisibility(true);
                    fragment.setUserVisibleHint(true);
                }
                mCurrentPrimaryItem = fragment;
            }
        }
            
    

    可以发现setUserVisibleHint 这个是在 FragmentPagerAdapter 进行调用的;利用 setPrimaryItem这个方法,来实现自己的延迟加载Adapter;

    实现步骤:

    1. 创建延迟加载接口LazyLoadCallBack:

              
      public interface LazyLoadCallBack {
          void onLoad();
      }
      
    2. 创建自己的验证加载Adapter:

      public class LazyFragmentPagerAdapter extends FragmentPagerAdapter {
      
          private List<Fragment> mFragments;
          private List<CharSequence> mTitles;
          private int mLastPosition = -1;
      
          public LazyFragmentPagerAdapter(FragmentManager fm) {
              super(fm);
          }
      
          public LazyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments, List<CharSequence> titles) {
              this(fm);
              this.mFragments = new ArrayList<>();
              this.mTitles = new ArrayList<>();
      
              mFragments.addAll(fragments);
              mTitles.addAll(titles);
      
              // 设置Load标记
              if (mFragments.size() > 0) {
                  for (Fragment f : mFragments) {
                      Bundle arguments = f.getArguments();
                      if (arguments == null) {
                          arguments = new Bundle();
                      }
                      arguments.putBoolean("load", false);
                      f.setArguments(arguments);
                  }
              }
      
              if (mTitles != null && mTitles.size() != mFragments.size()) {
                  throw new IllegalArgumentException("Title size must equals Fragment size");
              }
          }
      
          @Override
          public CharSequence getPageTitle(int position) {
              return mTitles.get(position);
          }
      
          @Override
          public Fragment getItem(int position) {
              return mFragments.get(position);
          }
      
          @Override
          public int getCount() {
              return mFragments.size();
          }
      
          @Override
          public void setPrimaryItem(ViewGroup container, int position, Object fragment) {
              super.setPrimaryItem(container, position, fragment);
              if (fragment instanceof Fragment) {
                  Fragment f = (Fragment) fragment;
                  if (f instanceof LazyLoadCallBack && mLastPosition != position
                          && f.isResumed()) {
                      mLastPosition = position;
                      if (!f.getArguments().getBoolean("load")) {
                          f.getArguments().putBoolean("load", true);
                          ((LazyLoadCallBack) f).onLoad();
                      }
                  }
              }
          }
      
          @Override
          public void destroyItem(ViewGroup container, int position, Object object) {
              super.destroyItem(container, position, object);
              if (object instanceof Fragment) {
                  Bundle arguments = ((Fragment) object).getArguments();
                  if (arguments != null) {
                      arguments.remove("load");
                  }
              }
          }
      }
      
    3. 创建ViewPager 的Adapter继承自步骤2的Adapter,代码省略;

      PagerAdapter adapter = new LazyFragmentPagerAdapter(getSupportFragmentManager(), fragments, titles);
          viewPager.setAdapter(adapter);
          tabLayout.setupWithViewPager(viewPager);    
      
    4. 如有延迟加载需求,让fragment 实现 LazyLoadCallBack,接口,让在其 onLoad方法中来进行数据请求;

    实例代码:

    https://github.com/zhaoyubetter/StateDemo/blob/master/app/src/main/java/state/better/statedemo/activity/lazy/LazyLoadActivity.java

    kotlin 形式实现请参考大神 momo :
    https://github.com/momodae/VolunteerUnion/blob/master/app/src/main/java/cz/volunteerunion/adapter/LazyFragmentPagerAdapter.kt

    相关文章

      网友评论

          本文标题:新方式 - 实现 viewPager fragment 延迟加载

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