多层嵌套后的 Fragment 懒加载实现

多层嵌套后的 Fragment 懒加载

印象中从 Feed 流应用流行开始,Fragment 懒加载变成了一个大家都需要关注的开发知识,关于 Fragment 的懒加载,网上有很多例子,GitHub 上也有很多例子,就连我自己在一年前也写过相关的文章。但是之前的应用可能最多的是一层 Activity + ViewPager 的 UI 层次,但是随着页面越来越复杂,越来越多的应用首页一个页面外层是一个 ViewPager 内部可能还嵌套着一层 ViewPager,这是之前的懒加载就可能不那么好用了。本文对于多层 ViewPager 的嵌套使用过程中,Fragment 主要的三个状态:第一次可见,每次可见,每次不可见,提供解决方案。

为什么要使用懒加载

在我们开发中经常会使用 ViewPager + Fragment 来创建多 tab 的页面,此时在 ViewPager 内部默认会帮我们缓存当页面前后两个页面的 Fragment 内容,如果使用了 setOffscreenPageLimit 方法,那么 ViewPager 初始化的时候将会缓存对应参数个 Fragment。为了增加用户体验我们往往会使用该方法来保证加载过的页面不被销毁,并留离开 tab 之前的状态(列表滑动距离等),而我们在使用 Fragment 的时候往往在创建完 View 后,就会开始网络请求等操作,如果存在上述的需求时,懒加载就显得尤为重要了,不仅可以节省用户流量,还可以在提高应用性能,给用户带来更加的体验。

ViewPager + Fragment 的懒加载实质上我们就在做三件事,就可以将上边所说的效果实现,那么就是找到每个 Fragment 第一对用户可见的时机,和每次 Fragment 对用户可见时机,以及每次 Framgment 对用户不可见的时机,来暴露给实现实现类做对应的网络请求或者网络请求中断时机。下面我们就来从常见的几种 UI 结构上一步步实现无论嵌套多少层,无论开发者使用的 hide show 还是 ViewPager 嵌套都能准确获取这三种状态的时机的一种懒加载实现方案。

单层 ViewPager + Fragment 懒加载

我们都知道 Fragment 生命周期按先后顺序有

onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume -> onPause -> onStop -> onDestroyView -> onDestroy -> onDetach

对于 ViewPager + Fragment 的实现我们需要关注的几个生命周期有:

onCreatedView + onActivityCreated + onResume + onPause + onDestroyView

以及非生命周期函数:

setUserVisibleHint + onHiddenChanged

对于单层 ViewPager + Fragment 可能是我们最常用的页面结构了,如网易云音乐的首页顶部的是三个 tab ,我们那网易云音乐作为例子:

对于这种 ViewPager + Fragment 结构,我们使用的过程中一般只包含是 4 种情况分别是:

  1. 使用 FragmentPagerAdapterFragmentPagerStateAdapter不设置 setOffscreenPageLimit

    • 左右滑动页面,每次只缓存下一个 Pager ,和上一个 Pager
    • 间隔的点击 tab 如从位于 tab1 的时候直接选择 tab3 或 tab4
  2. 使用 FragmentPagerAdapterFragmentPagerStateAdapter 设置 setOffscreenPageLimit 为 tab 总数

    • 左右滑动页面,每次只缓存下一个 Pager ,和上一个 Pager
    • 间隔的点击 tab 如从位于 tab1 的时候直接选择 tab3 或 tab4
  3. 进入其他页面或者用户按 home 键回到桌面,当前 ViewPager 页面变成不见状态。

对于 FragmentPagerAdapterFragmentPagerStateAdapter 的区别在于在于,前者在 Fragment 不见的时候将不会 detach ,而后者将会销毁 Fragmentdetach 掉。

实际上这也是所有 ViewPager 的操作情况。

  • 第一种情况不设置 setOffscreenPageLimit 左右滑动页面/或者每次选择相邻 tab 的情况 FragmentPagerAdapterFragmentPagerStateAdapter 有所区别
 BottomTabFragment1  setUserVisibleHint false
 BottomTabFragment2  setUserVisibleHint false
 BottomTabFragment1  setUserVisibleHint true

 BottomTabFragment1  onCreateView
 BottomTabFragment1  onActivityCreated 
 BottomTabFragment1  onResume  

 BottomTabFragment2  onCreateView
 BottomTabFragment2  onActivityCreated 
 BottomTabFragment2  onResume   

 //滑动到 Tab 2
 BottomTabFragment3  setUserVisibleHint false
 BottomTabFragment1  setUserVisibleHint false
 BottomTabFragment2  setUserVisibleHint true

 BottomTabFragment3  onCreateView
 BottomTabFragment3  onActivityCreated 
 BottomTabFragment3 onResume  

 //跳过 Tab3 直接选择 Tab4
 BottomTabFragment4  setUserVisibleHint false
 BottomTabFragment2  setUserVisibleHint false
 BottomTabFragment4  setUserVisibleHint true

 BottomTabFragment4  onCreateView
 BottomTabFragment4  onActivityCreated 
 BottomTabFragment4  onResume   

 BottomTabFragment2  onPause 
 BottomTabFragment2  onDestroyView

 // FragmentPagerStateAdapter 会走一下两个生命周期方法
 BottomTabFragment2  onDestroy 
 BottomTabFragment2  onDetach  

 BottomTabFragment1  onPause 
 BottomTabFragment1  onDestroyView

 // FragmentPagerStateAdapter 会走一下两个生命周期方法
 BottomTabFragment1  onDestroy 
 BottomTabFragment1  onDetach 

 // 用户回到桌面 再回到当前 APP 打开其他页面当前页面的生命周期也是这样的
 BottomTabFragment3  onPause 
 BottomTabFragment4  onPause 
 BottomTabFragment3  onStop 
 BottomTabFragment4  onStop 

 BottomTabFragment3 onResume  
 BottomTabFragment4 onResume  

  • 第二种情况设置 setOffscreenPageLimit 为 Pager 的个数时候,左右滑动页面/或者每次选择相邻 tab 的情况 FragmentPagerAdapter 和 FragmentPagerStateAdapter 没有区别
  BottomTabFragment1  setUserVisibleHint false
  BottomTabFragment2  setUserVisibleHint false
  BottomTabFragment3  setUserVisibleHint false
  BottomTabFragment4  setUserVisibleHint false

  BottomTabFragment1  setUserVisibleHint true
  BottomTabFragment1  onCreateView
  BottomTabFragment1  onActivityCreated 
  BottomTabFragment1 onResume  

  BottomTabFragment2  onCreateView
  BottomTabFragment2  onActivityCreated 

  BottomTabFragment3  onCreateView
  BottomTabFragment3  onActivityCreated 

  BottomTabFragment4  onCreateView
  BottomTabFragment4  onActivityCreated 

  BottomTabFragment2 onResume  
  BottomTabFragment3 onResume  
  BottomTabFragment4 onResume 

  //选择 Tab2
  BottomTabFragment1  setUserVisibleHint false
  BottomTabFragment2  setUserVisibleHint true

 //跳过 Tab3 直接选择 Tab4
  BottomTabFragment2  setUserVisibleHint false
  BottomTabFragment4  setUserVisibleHint true

  // 用户回到桌面 再回到当前 APP 打开其他页面当前页面的生命周期也是这样的
 BottomTabFragment1  onPause 
 BottomTabFragment2  onPause 
 BottomTabFragment3  onPause 
 BottomTabFragment4  onPause  

 BottomTabFragment1 onResume  
 BottomTabFragment2 onResume  
 BottomTabFragment3 onResume  
 BottomTabFragment4 onResume

可以看出第一次执行 setUserVisibleHint(boolean isVisibleToUser) 除了可见的 Fragment 外都为 false,还可以看出除了这一点不同以外,所有的 Fragment 都走到了生命周期 onResume 阶段。而选择相邻 tab 的时候已经初始化完成的Fragment 并不再重新走生命周期方法,只是 setUserVisibleHint(boolean isVisibleToUser) 为 true。当用户进入其他页面的时候所有 ViewPager 缓存的 Fragment 都会调用 onPause 生命周期函数,当再次回到当前页面的时候都会调用 onResume。

能发现这一点,其实对于单层 ViewPager 嵌套 Fragment 可见状态的把握其实已经很明显了。下面给出我的解决方案:

  1. 对于 Fragment 可见状态的判断需要设置两个标志位 ,Fragment View 创建完成的标志位 isViewCreatedFragment 第一次创建的标志位 mIsFirstVisible
  2. 为了获得 Fragment 不可见的状态,和再次回到可见状态的判断,我们还需要增加一个 currentVisibleState 标志位,该标志位在 onResume 中和 onPause 中结合 getUserVisibleHint 的返回值来决定是否应该回调可见和不可见状态函数。

整个可见过程判断逻辑如下图所示

接下来我们就来看下具体实现&#

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值