7.ViewPager原理分析

ViewPager原理分析

  1. ViewPager的加载方式
  • 预加载 在进入还没有显示的页面前,就请求这个页面的数据;默认是会进行预加载的,因为setOffscreenPageLimit(0)无效,源码如下:
    public void setOffscreenPageLimit(int limit) {
        //将离屏预加载页面数量设置成0无效,会被置为1
        if (limit < DEFAULT_OFFSCREEN_PAGES = 1) {
            limit = DEFAULT_OFFSCREEN_PAGES = 1;
        }
        //之前的离屏页面数量和现在设置的离屏数量不等时,重置新的离屏数量并刷新
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            //刷新
            populate();
        }
    }
    
    • 优点:节约时间,用户体验更好;
    • 缺点:浪费流量和内存资源.
    • 通过这个方法setOffscreenPageLimit(int limit)设置预加载左边和右边的页面数量,默认值是1 ,设置值为0无效,这个方法中限制了最小值是1
  • 懒加载 在页面显示的时候再请求数据
    • 目前大部分的app都采用了懒加载这种方式
  1. ViewPager中重要的方法populate()在哪几个地方使用到了?
  • setOffscreenPageLimit()
  • smoothScrollTo()
  • onMeasure()
  1. ViewPager中重要的方法populate()分析?这里的mAdapter是PageAdapter的实现类
    总结:
    mAdapter.instantiateItem()mAdapter.setPrimaryItem()方法中都包含了setUserVisibleHint()这个方法,这两个方法执行后才会执行mAdapter.finishUpdate()方法,这个方法中会执行Fragment的生命周期.
    也就是说setUserVisibleHint()方法在Fragment生命周期之前执行.
  • mAdapter.startUpdate() 开始更新数据
    • 开始适配
  • mAdapter.instantiateItem() 实例化(ItemInfo.object)item
    • 创建适配的Item数据
    • 在这个方法中会执行如下代码:
      fragment.setUserVisibleHint(false);
      这里的变量fragment是点击tab的那个Fragment
  • mAdapter.destroyItem() 销毁(ItemInfo.object)item
    • 销毁适配的Item数据
  • mAdapter.setPrimaryItem() 设置基本的(ItemInfo.object)item
    • 设置当前显示的Item
    • 这个方法中会依次执行如下代码:
      • mCurrentPrimaryItem.setUserVisibleHint(false);
        这里的变量mCurrentPrimaryItem是当前页面展示的那个Fragment
      • fragment.setUserVisibleHint(true);
        这里的变量fragment是点击tab的那个Fragment
  • mAdapter.finishUpdate(); 完成更新数据
    • 通过事务的方式,执行Fragment生命周期函数
  1. PageAdapter的实现类
  • FragmentStatePagerAdapter 不可以缓存
  • FragmentPagerAdapter 可以缓存,所以通常情况下用这个适配器

ViewPager2原理分析

ViewPager2和ViewPager的区别?

  • 底层实现方式是RecyclerView,所以ViewPager2性能更好;
    源码构造函数中初始化RecyclerView的代码如下:
    mRecyclerView = new RecyclerViewImpl(context);
  • 适配器是FragmentStateAdapter,继承子RecyclerView.Adapter;
    使用的代码如下:
    setAdapter(Adapter adapter)
  • ViewPager2可以实现垂直方向滑动,因为底层实现是RecyclerView;
    使用的代码如下:
    setOrientation(RecyclerView.VERTICAL)
  • 使用LifecycleFragment的生命周期进行管理,在FragmentStateAdapter.java里面进行Fragment生命周期管理;
  • 默认是懒加载处理方式
    可以通过setOffscreenPageLimit()方法实现预加载功能

总结:
ViewPager2底层实现是RecyclerView,而RecyclerView的缓存mCacheViews最大值是2;但是ViewPager2在滑动的过程中,会有一个预取(GapWorker)GapWorker.prefetch()的操作,这个操作会去更改缓存大小,在原有缓存大小为2的基础上再加1,从而更改缓存mCacheViews大小最大值为3,所以ViewPager2在滑动的过程中,会缓存加载过的2Fragment,同时会缓存1个还没有加载的Fragment,这个操作就叫做预取prefetch();最终使得缓存中的最多缓存3Fragment.我们可以通过这个方法关闭预取prefetch:
((RecyclerView) (mViewPager2.getChildAt(0))).getLayoutManager().setItemPrefetchEnabled(false);
说明:
ViewPager2.getChildAt(0)就可以得到底层实现的RecyclerView,从而使缓存mCacheViews的最大值是2.

为什么RecyclerView中有fling(抛掷)事件,ViewPager2中为什么没有?怎么实现fling?

ViewPager2底层是通过RecyclerView实现的,所以我们去分析RecyclerView中的onTouch事件处理方法中的ACTION_UP抬起事件,这个事件中会去处理fling()事件.
RecyclerView中没有分发fling?还是分发了fling事件但是ViewPager2中没有处理fling
SnapHelper作用:就是用来帮助RecyclerView进行滚动的.
比如:RecyclerView要在ViewPager2中进行滑动处理,SnapHelper就可以帮助RecyclerView继续滚动或者回弹,达到画廊Gallery那种继续滚动或者回弹的效果.

  1. 设置fling监听
    • initialize()
      • 切入点:在ViewPager2的构造函数中的初始化过程中设置fling监听.
    • mPagerSnapHelper.attachToRecyclerView(mRecyclerView); @ViewPager2.java
      • 在ViewPager2源码初始化过程中,将SnapHelper绑定到RecyclerView
    • setupCallbacks(); @SnapHelper.java
    • mRecyclerView.setOnFlingListener(this); @SnapHelper.java
      • 设置Fling监听
  2. 处理fling事件
    • RecyclerView.onTouchEvent->ACTION_UP->fling()
      • 切入点:在ViewPager2的底层实现RecyclerView中,事件处理过程onTouchEvent的手指抬起过程,ACTION_UP中对fling抛掷事件进行处理
    • fling(int velocityX, int velocityY) @RecyclerView
    • mOnFlingListener.onFling() @RecyclerView
      • 这个就是ViewPager2中RecyclerView执行的fling()事件处理
    • SnapHelper.onFling()
      • 最终回调到SnapHelper中的onFling方法
    • snapFromFling()
    • (PagerSnapHelper)SnapHelper.findTargetSnapPosition()
    • // Return the position of the first child from the center, in the direction of the fling
      final boolean forwardDirection = isForwardFling(layoutManager, velocityX, velocityY);
      if (forwardDirection && closestChildAfterCenter != null) {
          return layoutManager.getPosition(closestChildAfterCenter);
      } else if (!forwardDirection && closestChildBeforeCenter != null) {
          return layoutManager.getPosition(closestChildBeforeCenter);
      }
      

总结:
ViewPager2通过将SnapHelper绑定RecyclerView上,实现对onFling()抛掷事件的处理.

还没有来得及学习的内容:
1. PhoneWindow手势处理;
2. 京东淘宝首页二级联动实战;
3. 锦鲤自定义View效果实现;
4. MaterialDesign入门
5. CoordinatorLayout布局
6. 约束布局
7. 自定义WebView
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值