ViewPager原理分析
- 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都采用了懒加载这种方式
- ViewPager中重要的方法populate()在哪几个地方使用到了?
- setOffscreenPageLimit()
- smoothScrollTo()
- onMeasure()
- 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生命周期函数
- PageAdapter的实现类
FragmentStatePagerAdapter
不可以缓存FragmentPagerAdapter
可以缓存,所以通常情况下用这个适配器
ViewPager2原理分析
ViewPager2和ViewPager的区别?
- 底层实现方式是
RecyclerView
,所以ViewPager2
性能更好;
源码构造函数中初始化RecyclerView的代码如下:
mRecyclerView = new RecyclerViewImpl(context);
- 适配器是
FragmentStateAdapter
,继承子RecyclerView.Adapter
;
使用的代码如下:
setAdapter(Adapter adapter)
ViewPager2
可以实现垂直方向滑动,因为底层实现是RecyclerView
;
使用的代码如下:
setOrientation(RecyclerView.VERTICAL)
- 使用
Lifecycle
对Fragment
的生命周期进行管理,在FragmentStateAdapter.java
里面进行Fragment
生命周期管理; - 默认是懒加载处理方式
可以通过setOffscreenPageLimit()
方法实现预加载功能
总结:
ViewPager2
底层实现是RecyclerView
,而RecyclerView
的缓存mCacheViews
最大值是2
;但是ViewPager2
在滑动的过程中,会有一个预取(GapWorker)GapWorker.prefetch()
的操作,这个操作会去更改缓存大小,在原有缓存大小为2
的基础上再加1
,从而更改缓存mCacheViews
大小最大值为3
,所以ViewPager2
在滑动的过程中,会缓存加载过的2
个Fragment
,同时会缓存1
个还没有加载的Fragment
,这个操作就叫做预取prefetch()
;最终使得缓存中的最多缓存3
个Fragment
.我们可以通过这个方法关闭预取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
那种继续滚动或者回弹的效果.
- 设置fling监听
- initialize()
切入点:
在ViewPager2的构造函数中的初始化过程中设置fling监听.
- mPagerSnapHelper.attachToRecyclerView(mRecyclerView); @ViewPager2.java
- 在ViewPager2源码初始化过程中,将SnapHelper绑定到RecyclerView
- setupCallbacks(); @SnapHelper.java
mRecyclerView.setOnFlingListener(this);
@SnapHelper.java- 设置Fling监听
- initialize()
- 处理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); }
- RecyclerView.onTouchEvent->ACTION_UP->fling()
总结:
ViewPager2
通过将SnapHelper
绑定RecyclerView
上,实现对onFling()
抛掷事件的处理.
还没有来得及学习的内容:
1. PhoneWindow手势处理;
2. 京东淘宝首页二级联动实战;
3. 锦鲤自定义View效果实现;
4. MaterialDesign入门
5. CoordinatorLayout布局
6. 约束布局
7. 自定义WebView