本文作者
作者:HitenDev
链接:
https://juejin.im/post/5cda3964f265da035d0c9d8f
本文由作者授权发布。
1 前言最近ViewPager2发布了1.0.0-alpha04版本,新增offscreenPageLimit功能,该功能在ViewPager上并不友好,现在官方将此功能延续下来,这回是骡子是马呢?赶紧拉出来溜溜;
阅读指南:
内容基于ViewPager21.0.0-alpha04版本讲解,由于正式版还未发布,如有功能变动有劳看官指出
内容重点:介绍ViewPager2的offscreenPageLimit特性和预加载机制,另外包括Adapter的状态和Fragment的生命周期等内容
2 ViewPager 顽疾
顽疾是什么鬼,没有这么严重吧。ViewPager有两个毛病:不能关闭预加载和更新Adapter不生效,所以开头我为什么说offscreenPageLimit在ViewPager上十分不友好;
本质上是因为offscreenPageLimit不能设置成0(设置成0就是想象中的关闭预加载);
上面是ViewPager默认情况下的加载示意图,当切换到当前页面时,会默认预加载左右两侧的布局到ViewPager中,尽管两侧的View并不可见的,我们称这种情况叫预加载;由于ViewPager对offscreenPageLimit设置了限制,页面的预加载是不可避免;
ViewPager
private static final int DEFAULT_OFFSCREEN_PAGES = 1;
public void setOffscreenPageLimit(int limit) {
if (limit //不允许小于1
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强制预加载的逻辑在Fragment配合ViewPager使用时依然存在.
Fragment懒加载前因后果
先说PagerAdapter:
PagerAdapter常用方法如下:
instantiateItem(ViewGroup container, int position)初始化ItemView,返回需要添加ItemView
destroyItem(iewGroup container, int position, Object object)销毁ItemView,移除指定的ItemView
isViewFromObject(View view, Object object)View和Object是否对应
setPrimaryItem(ViewGroup container, int position, Object object) 当前页面的主Item
getCount()获取Item个数
先说setPrimaryItem(ViewGroup container, int position, Object object),该方法表示当前页面正在显示主要Item,何为主要Item?如果预加载的ItemView已经划入屏幕,当前的PrimaryItem依然不会改变,除非新的ItemView完全划入屏幕,且滑动已经停止才会判断;
由于ViewPager不可避免的进行布局预加载,造成PagerAdapter必须提前调用instantiateItem(ViewGroup container, int position)方法,instantiateItem()是创建ItemView的唯一入口方法,所以PagerAdapter的实现类FragmentPagerAdapter和FragmentStatePagerAdapter必须抓住该方法进行Fragment对象的创建;
碰巧的是,FragmentPagerAdapter和FragmentStatePagerAdapter一股脑的在instantiateItem()中进行创建且进行add或attach操作,并没有在setPrimaryItem()方法中对Fragment进行操作;
因此,预加载会导致不可见的Fragment一股脑的调用onCreate、onCreateView、onResume等方法,用户只能通过Fragment.setUserVisibleHint()方法进行识别;
大多数的懒加载都是对Fragment做手脚,结合生命周期方法和setUserVisibleHint状态,控制数据延迟加载,而布局只能提前进入;
3 ViewPager2 基本使用build.gradle引入
implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha04'
布局文件添加
<androidx.viewpager2.widget.ViewPager2android:id="@+id/view_pager"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" />
设置ViewHolder+Adapter
ViewPager2 viewPager = findViewById(R.id.view_pager2);
viewPager.setAdapter(new RecyclerView.Adapter() {
@Overridepub