美文网首页
ViewPager的缓存页面 与 预加载

ViewPager的缓存页面 与 预加载

作者: 壹元伍角叁分 | 来源:发表于2021-09-17 14:12 被阅读0次

前言

  1. 缓存的目的是为什么?

    答:为了预加载。

  2. 什么是预加载?

    答:Fragment切换的时候,会预先加载未可见的Fragment,就是预加载。

  3. 在缓存页面setOffscreenPageLimit(int limit) 是什么?

    答:可以设置缓存页面,设置3就是缓存6个Fragment,设置4就是缓存8个Fragment。

  4. 为什么这个函数设置 0 无效,为什么缓存的页面数不能低于1?

    答:setOffscreenPageLimit 看源码分析,因为就算是设置0,默认内部也会被修改成1。

  5. 在预加载 - setOffscreenPageLimit(int limit) 是什么?

    答:可以设置预加载,设置2就是预加载T2、T3。默认打开T1,预加载T2、T3;默认打开T2,预加载T3、T4

  6. 预加载会带来什么问题?怎么解决?

    答:会带来问题:1.预加载的越多就会越卡;2.一个Fragment占用 1M,5个就(5*1M),累计到后面就会OOM;3.如果预加载的Fragment在请求网络,不仅浪费流量,还会很卡顿.......解决办法:使用懒加载,来解决预加载带来的问题。

  7. 懒加载 是什么?

    答:防止预加载,用到才加载,可见才加载,不可见就不加载。
    懒加载,其实也就是延迟加载,就是等到该页面的UI展示给用户时,再加载该页面的数据(从网络、数据库等),而不是依靠 ViewPager预加载机制提前加载两三个,甚至更多页面的数据。
    目的:这样可以提高所属Activity的初始化速度,也可以为用户节省流量。而这种懒加载的方式也已经正在被诸多APP所采用。

源码解析

ViewPager.onMeasure(int widthMeasureSpec, int heightMeasureSpec)
//这个是最重要的步骤
--> populate();
    --> populate(mCurItem);
        //准备适配
        --> mAdapter.startUpdate(this);
            -->  startUpdate((View) container);
        --> curItem = addNewItem(mCurItem, curIndex);
            //创建适配的item数据
            --> ii.object = mAdapter.instantiateItem(this, position);
                --> fragment.setMenuVisibility(false);@FragmentPagerAdapter
                --> fragment.setUserVisibleHint(false);
        //销毁适配的item数据
        --> mAdapter.destroyItem(this, pos, ii.object);
            --> mCurTransaction = mFragmentManager.beginTransaction();@FragmentPagerAdapter
        //设置当前显示的item数据
        --> mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
            -->  if (fragment != mCurrentPrimaryItem) {
                     if (mCurrentPrimaryItem != null) {
                         //重置上一个item的属性
                         mCurrentPrimaryItem.setMenuVisibility(false);
                         mCurrentPrimaryItem.setUserVisibleHint(false);
                     }
                     //设置当前item的属性
                     fragment.setMenuVisibility(true);
                     fragment.setUserVisibleHint(true);
                     mCurrentPrimaryItem = fragment;
                 }
        //完成适配。接着才开始执行fragment的生命周期
        --> mAdapter.finishUpdate(this);
            --> mCurTransaction.commitNowAllowingStateLoss();
setOffscreenPageLimit(int limit)
//DEFAULT_OFFSCREEN_PAGES = 1,如果limit<1,则设置为1。也就解释了为什么设置0无效。
--> 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(),具体分析同上
       populate();
    }

流程分析

1、初次进入:

scom.xh.myviewpagerfragmentapp D/BlankFragment: etUserVisibleHint: tab=1,isVisibleToUser=false
com.xh.myviewpagerfragmentapp D/BlankFragment: setUserVisibleHint: tab=2,isVisibleToUser=false
com.xh.myviewpagerfragmentapp D/BlankFragment: setUserVisibleHint: tab=1,isVisibleToUser=true
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=2
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=2

2、从tab1点击进入tab3:

//下面两个是由mAdapter.instantiateItem(this, position)函数触发;
setUserVisibleHint: tab=3,isVisibleToUser=false //加载tab3
setUserVisibleHint: tab=4,isVisibleToUser=false //预加载tab4
//下面两个是由mAdapter.setPrimaryItem(this, mCurItem, curItem.object);函数触发;
setUserVisibleHint: tab=1,isVisibleToUser=false //重置tab1
setUserVisibleHint: tab=3,isVisibleToUser=true  //显示tab3
//下面才开始执行fragment的生命周期函数,由mAdapter.finishUpdate(this)触发
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onAttach: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreate: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=3
com.xh.myviewpagerfragmentapp D/BlankFragment: onCreateView: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onViewCreated: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onActivityCreated: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onStart: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onResume: tab=4
com.xh.myviewpagerfragmentapp D/BlankFragment: onPause: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onStop: tab=1
com.xh.myviewpagerfragmentapp D/BlankFragment: onDestroyView: tab=1

使用懒加载流程:

1、在setUserVisibleHint(boolean isVisibleToUser),判断参数isVisibleToUser为true时才去加载数据,false则停止加载

 override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
    if (isVisibleToUser) {
         startDoThings()
    } else {
         stopDoThings()
        }
    }

2、解决崩溃:由于setUserVisibleHint(boolean isVisibleToUser)在onCreateView()之前执行,有可能view还未被创建。所以需要设置一个tag,在onCreateView()中置为true。
然后在tag为true时才去加载/停止加载数据

override fun onCreateView(inflater: LayoutInflater, container:ViewGroup?,
        savedInstanceState: Bundle?): View? {
    ...
    viewCreate = true
    ...
}

override fun onDestroyView() {
    super.onDestroyView()
    ...
    viewCreate = false
    ...
}

 override fun setUserVisibleHint(isVisibleToUser: Boolean) {
    super.setUserVisibleHint(isVisibleToUser) 
    if (viewCreate) {
       if (isVisibleToUser) {
          startDoThings()
       } else {
          stopDoThings()
       }
    }
}

3、解决第一次进入不加载:第一次进入,setUserVisibleHint(boolean isVisibleToUser)在onCreateView()之前执行,加载数据的逻辑并未执行,
所以需要我们在onCreateView()中手动执行加载逻辑,在getUserVisibleHint()为true的时候执行。

override fun onCreateView(inflater: LayoutInflater, container:ViewGroup?,savedInstanceState: Bundle?): View? {
     ...
     viewCreate = true
     if (userVisibleHint) {
         userVisibleHint = true
     }
     ...
}

总结

Fragment 生命周期按先后顺序:
onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume ->
onPause -> onStop -> onDestroyView -> onDestroy -> onDetach

ViewPager + Fragment 的实现我们需要关注的几个生命周期有: onCreatedView + onResume + onPause + onDestroyView非生命周期函数:setUserVisibleHint + onHiddenChanged

相关文章

  • ViewPager的缓存页面 与 预加载

    前言 缓存的目的是为什么?答:为了预加载。 什么是预加载?答:Fragment切换的时候,会预先加载未可见的Fra...

  • ViewPager<第五篇>:预加载和懒加载

    预加载 ViewPager为什么让滑动流畅,默认将左右两个页面加载到了内存,这叫做ViewPager的预加载,但是...

  • viewpager的缓存加载机制

    viewpager有缓存预加载机制,主要使用setOffscreenPageLimit(int limit) 1....

  • Viewpager和Fragment的懒加载机制

    一、背景 ViewPager默认加载当前页面,而且预加载当前页面的前后两个页面数据(即同时会加载3个页面的数据),...

  • 深入解析ViewPager懒加载

    前言 ViewPager默认情况的加载,会默认预加载一个的布局到ViewPager中,这就时ViewPager的预...

  • Fragment懒加载(一)

    用多viewpager+fragment的朋友都知道viewpager有预加载机制,如果你每个页面都有请求网络的操...

  • Fragment+ViewPager懒加载

      ViewPager的预加载机制,会自动加载左右两边的页面,影响性能,甚至出现卡顿。解决方案如下:

  • Fragment懒加载

    在ViewPager与Fragment一起使用时,由于ViewPager的特性,Fragment会预加载,但是我们...

  • Android Fragment 懒加载

    ViewPager默认会去预加载当前页面前后的两个Fragment。为了防止加载多个Fragment时出现切换卡顿...

  • 禁止ViewPager预加载问题

    首先来说明一下,什么是ViewPager的预加载:ViewPager有一个 “预加载”的机制,默认会把ViewPa...

网友评论

      本文标题:ViewPager的缓存页面 与 预加载

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