针对 Fragment 懒加载优化,以下是分步解决方案:
一、问题背景
在 ViewPager/ViewPager2 中,默认会预加载相邻 Fragment,导致不必要的资源消耗和数据请求。需实现 按需加载(当 Fragment 对用户可见时再加载数据)。
二、核心方案
结合 Fragment 生命周期和可见性判断,通过 基类封装 + 生命周期观察 实现懒加载控制。
三、具体实现
1. 基础版方案(适合 ViewPager)
实现逻辑:
- 利用
setUserVisibleHint
(已废弃但兼容旧版本)或onHiddenChanged
判断可见性。 - 结合
onViewCreated
和onDestroyView
管理数据加载与释放。
代码示例:
kotlin
abstract class LazyFragment : Fragment() {
private var isViewCreated = false
private var isFirstLoad = true // 首次加载标记
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isViewCreated = true
tryLoadData()
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
tryLoadData()
}
private fun tryLoadData() {
if (isViewCreated && userVisibleHint && isFirstLoad) {
onLazyLoad()
isFirstLoad = false
}
}
abstract fun onLazyLoad() // 懒加载数据
override fun onDestroyView() {
super.onDestroyView()
isViewCreated = false
isFirstLoad = true // 重置状态
}
}
2. 增强版方案(支持 ViewPager2 + Lifecycle)
实现逻辑:
- 使用
FragmentTransaction.setMaxLifecycle()
(限制非活跃 Fragment 生命周期)。 - 结合
Lifecycle.State
精确控制加载时机。
代码示例:
kotlin
abstract class LazyFragment : Fragment() {
private var isViewCreated = false
private var isFirstLoad = true
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isViewCreated = true
observeLifecycle()
}
private fun observeLifecycle() {
viewLifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_RESUME && isVisibleToUser) {
tryLoadData()
}
}
})
}
private fun tryLoadData() {
if (isViewCreated && isVisibleToUser && isFirstLoad) {
onLazyLoad()
isFirstLoad = false
}
}
abstract fun onLazyLoad()
}
3. ViewPager2 配置优化
kotlin
// 设置预加载数量为 0(默认已优化,但可进一步限制)
viewPager2.offscreenPageLimit = 0
// 使用 FragmentStateAdapter 自动管理生命周期
class MyAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
四、进阶优化技巧
-
数据缓存与刷新
- 使用
ViewModel
保存已加载数据,避免重复请求。 - 添加
onVisibleRefresh()
方法在再次可见时刷新数据。
- 使用
-
嵌套 Fragment 处理
- 重写
isVisibleToUser
逻辑,考虑父 Fragment 的可见性。
- 重写
-
生命周期精准控制
kotlinoverride fun onPause() { super.onPause() if (isVisibleToUser) { // 释放资源(如暂停视频播放) } }
五、方案对比
方案 | 优点 | 缺点 |
---|---|---|
setUserVisibleHint | 兼容旧版本 | 已废弃,可能不适用于新场景 |
Lifecycle 观察 | 官方推荐,生命周期感知精准 | 需要处理 Fragment 嵌套情况 |
setMaxLifecycle | 彻底禁止预加载,减少内存占用 | 需要 API 28+,配置稍复杂 |
六、注意事项
- 避免内存泄漏 :在
onDestroyView
中释放资源。 - 状态保存 :使用
onSaveInstanceState
保存加载状态。 - Fragment 嵌套:递归检查父 Fragment 的可见性。
最终方案选择:
- 新项目建议使用 Lifecycle 观察 + ViewPager2。
- 旧项目升级可先用 增强版基础方案 过渡。