android x fragment,AndroidX的Fragment懒加载

本文详细介绍了在AndroidX之前和之后,如何实现Fragment的懒加载。在AndroidX之前,通过ViewPager和FragmentTransaction控制模式有不同的懒加载策略,如通过onResume、setUserVisibleHint和onHiddenChanged方法。而在AndroidX中,新增了setMaxLifecycle方法,使得可以更精确地控制Fragment的生命周期,简化了懒加载的实现。推荐在AndroidX中使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT设置适配器,以便在onResume中安全地进行懒加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AndroidX之前的Fragment懒加载

在AndroidX之前,Fragment的使用有两种方式:

使用ViewPager+Fragment模式

通过FragmentTransaction控制Fragment的使用

1.AndroidX之前ViewPager模式的懒加载

分析:

由于ViewPager的缓存机制offscreenPageLimit始终>=1,所以ViewPager会缓存布局屏幕外的Fragment>=1个,被缓存的屏幕外的Fragment也会像屏幕可见的Fragment一样执行生命周期到onResume,并且在用户滑动后缓存的Fragment由不可见到可见时并不会调用onResume。根据ViewPager调用Fragment的方法顺序:

setUserVisibleHint->onAttach->onCreate->onCreateView->onViewCreated->onActivityCreated->onStart->onResume

所以,在androidX之前,ViewPager模式的懒加载方式是:

对于第一个可见的Fragment,在onResume方法中执行懒加载请求数据

对于缓存的Fragment由不可见到可见时,通过setUserVisibleHint方法中执行懒加载请求数据

abstract class LazyFragment {

// Fragment的数据是否加载过

private var isLoaded = false

// Fragment是否可见

private var isVisibleToUser = false

// 是否加载过onResume

private var isCallResume = false

override fun onResume() {

super.onResume()

isCallResume = true

checkLazy()

}

private fun checkLazy() {

if (!isLoaded && isVisibleToUser && isCallResume) {

lazyInit()

isLoaded = true

}

}

override fun setUserVisibleHint(isVisibleToUser: Boolean) {

super.setUserVisibleHint(isVisibleToUser)

this.isVisibleToUser = isVisibleToUser

checkLazy()

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

isVisibleToUser = false

isCallResume = false

}

abstract fun lazyInit()

}

需要注意的是ViewPager嵌套加载,对于第二个加载的ViewPager的数据绑定一定要放在上一个Fragment的lazyInit懒加载方法中进行初始化。如下:

override fun lazyInit() {

view_pager?.apply {

adapter = FragmentLazyStatePageAdapter(

childFragmentManager,

generateTextFragments(4),

generateTextFragmentTitles(4)

)

}

tab_layout?.setupWithViewPager(view_pager)

}

2.AndroidX之前FragmentTransaction控制模式的懒加载

通过FrameLayout绑定Fragment时,我们要通过FragmentTransaction进行控制。

FragmentTransaction transaction = FragmentManager.beginTransaction();

// Fragment绑定FrameLayout

transaction.add(containerViewId, fragment, fgTag);

// 控制Fragment的显示/隐藏

transaction.show(fragment);

transaction.hide(fragment);

// 提交

transaction.commit();

对于一个FrameLayout绑定多个Fragment,并每次只显示一个,我们可以这样通过FragmentTransaction控制Fragment的行为,代码如下:

// FrameLayout绑定多个Fragment

private fun loadFragmentsTransaction(

@IdRes containerViewId: Int, showPosition: Int,

fragmentManager: FragmentManager, vararg fragments: Fragment) {

if (fragments.isNotEmpty()) {

fragmentManager.beginTransaction().apply {

for (index in fragments.indices) {

val fragment = fragments[index]

add(containerViewId, fragment, fragment.javaClass.name)

if (showPosition != index) {

hide(fragment)

}

}

}.commit()

} else {

throw IllegalStateException(

"fragments must not empty"

)

}

}

// 控制Fragment的显示/隐藏

private fun showHideFragmentTransaction(fragmentManager: FragmentManager, showFragment: Fragment) {

fragmentManager.beginTransaction().apply {

show(showFragment)

//获取其中所有的fragment,其他的fragment进行隐藏

val fragments = fragmentManager.fragments

for (fragment in fragments) {

if (fragment != showFragment) {

hide(fragment)

}

}

}.commit()

FragmentTransaction模式下的Fragment会全部执行生命周期至onResume,并且会调用onHiddenChanged表示Fragment隐藏是否发生改变,但是第一个可见的Fragment因为是可见的,所以并不会调用onHiddenChanged。

所以,anroidX之前FragmentTransaction模式下的懒加载:

第一个可见Fragment通过onResume方法和isHidden变量进行判断进行懒加载。

其它由不可见到可见的Fragment,因为已经执行了onResume方法,所以通过onHiddenChanged方法进行懒加载:

abstract class LazyFragment {

// Fragment的数据是否加载过

private var isLoaded = false

// Fragment是否可见

private var isVisibleToUser = false

// 是否加载过onResume

private var isCallResume = false

// 是否调用过setUserVisibleHint,表明是ViewPager模式

private var isCallUserVisibleHint = false

override fun onResume() {

super.onResume()

isCallResume = true

if (!isCallUserVisibleHint) {

// 不是ViewPager模式

isVisibleToUser = !isHidden

}

checkLazy()

}

private fun checkLazy() {

if (!isLoaded && isVisibleToUser && isCallResume) {

lazyInit()

isLoaded = true

}

}

override fun onHiddenChanged(hidden: Boolean) {

super.onHiddenChanged(hidden)

isVisibleToUser = !hidden

checkLazy()

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

isVisibleToUser = false

isCallUserVisibleHint = false

isCallResume = false

}

abstract fun lazyInit()

}

AndroidX之前的适配ViewPager和FragmentTransaction的懒加载

abstract class LazyFragment : LogFragment() {

// Fragment的数据是否加载过

private var isLoaded = false

// Fragment是否可见

private var isVisibleToUser = false

// 是否加载过onResume

private var isCallResume = false

// 是否调用过setUserVisibleHint,表明是ViewPager模式

private var isCallUserVisibleHint = false

override fun onResume() {

super.onResume()

isCallResume = true

if (!isCallUserVisibleHint) {

// 不是ViewPager模式

isVisibleToUser = !isHidden

}

checkLazy()

}

private fun checkLazy() {

if (!isLoaded && isVisibleToUser && isCallResume) {

lazyInit()

isLoaded = true

}

}

override fun onHiddenChanged(hidden: Boolean) {

super.onHiddenChanged(hidden)

isVisibleToUser = !hidden

checkLazy()

}

override fun setUserVisibleHint(isVisibleToUser: Boolean) {

super.setUserVisibleHint(isVisibleToUser)

this.isVisibleToUser = isVisibleToUser

isCallUserVisibleHint = true

checkLazy()

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

isVisibleToUser = false

isCallUserVisibleHint = false

isCallResume = false

}

abstract fun lazyInit()

}

AndroidX的Fragment懒加载

通过上面的分析我们知道在AndroidX之前,不管Fragment是否可见,都执行了onResume方法,这就违背了生命周期中onResume的设计本意了。所以在安卓X中,在FragmentTransaction类中增加了一个方法setMaxLifecycle(@NonNull Fragment fragment,@NonNull Lifecycle.State state),我们可以通过这个方法的第二个参数设置Fragment最大能执行到哪个生命周期方法。

对于不可见的Fragment,我们可以通过FragmentTransaction. setMaxLifecycle(fragment, Lifecycle.State.STARTED)设置Fragment最大执行到onStart()方法。

对于可见的Fragment,通过FragmentTransaction. setMaxLifecycle(fragment, Lifecycle.State.RESUMED)设置Fragment最大执行到onResume()方法。

AndroidX的ViewPager2+Fragment的懒加载:

ViewPager2加载Fragment使用了新的适配器FragmentStateAdapter,在新的FragmentStateAdapter中已经对Fragment的是否可见对FragmentTransaction. setMaxLifecycle(fragment, Lifecycle.State.STARTED)设置了不同的参数。所以我们可以放心的在onResume方法中进行懒加载:

abstract class LazyXFragment {

private var isLoaded = false //是否已经加载过数据

override fun onResume() {

super.onResume()

if (!isLoaded) {

lazyInit()

isLoaded = true

}

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

}

abstract fun lazyInit()

}

AndroidX的ViewPager+Fragment的懒加载:

在AndroidX中分别对ViewPager+Fragment的两个适配器FragmentPagerAdapter、FragmentStatePagerAdapter对setMaxLifecycle方法进行适配。只要我们在适配器的第二个构造参数设置为:

BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT就表示通过setMaxLifecycle设置执行的最大的生命周期,并不执行setUserVisibleHint方法

BEHAVIOR_SET_USER_VISIBLE_HINT则跟AndroidX之前的ViewPager一样,即执行setUserVisibleHint又执行onResume。

所以,如果你的项目如果升级到了AndroidX,可以在继承FragmentPagerAdapter、FragmentStatePagerAdapter两个适配器的类的第二个构造参数设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT。

// 设置FragmentPagerAdapter 适配setMaxLifecycle方法

open class FragmentLazyPagerAdapter(

fragmentManager: FragmentManager,

private val fragments: MutableList,

private val titles: MutableList

) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

override fun getItem(position: Int): Fragment {

return fragments[position]

}

override fun getCount(): Int {

return fragments.size

}

override fun getPageTitle(position: Int): CharSequence? {

return titles[position]

}

}

// 设置FragmentStatePagerAdapter 适配setMaxLifecycle方法

open class FragmentLazyStatePageAdapter(

fragmentManager: FragmentManager,

private val fragments: MutableList,

private val titles: MutableList

) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

override fun getItem(position: Int): Fragment = fragments[position]

override fun getCount(): Int = fragments.size

override fun getPageTitle(position: Int): CharSequence? = titles[position]

}

如果我们第二个构造参数不设置,就会默认为BEHAVIOR_SET_USER_VISIBLE_HINT则做旧模式那套。

所以,在AndroidX中,分别对ViewPager+Fragmen两个适配器FragmentPagerAdapter、FragmentStatePagerAdapter对setMaxLifecycle方法进行适配,那么其懒加载和ViewPager2一样:

abstract class LazyXFragment {

private var isLoaded = false //是否已经加载过数据

override fun onResume() {

super.onResume()

if (!isLoaded) {

lazyInit()

isLoaded = true

}

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

}

abstract fun lazyInit()

}

AndroidX的FragmentTransaction模式的懒加载:

我们可以通过FragmentTransaction对是否可见的Fragment进行设置setMaxLifecycle方法:

AndroidX之前增加,显示/隐藏是这样写的:

// FrameLayout绑定多个Fragment

private fun loadFragmentsTransaction(

@IdRes containerViewId: Int, showPosition: Int,

fragmentManager: FragmentManager, vararg fragments: Fragment) {

if (fragments.isNotEmpty()) {

fragmentManager.beginTransaction().apply {

for (index in fragments.indices) {

val fragment = fragments[index]

add(containerViewId, fragment, fragment.javaClass.name)

if (showPosition != index) {

hide(fragment)

}

}

}.commit()

} else {

throw IllegalStateException(

"fragments must not empty"

)

}

}

// 控制Fragment的显示/隐藏

private fun showHideFragmentTransaction(fragmentManager: FragmentManager, showFragment: Fragment) {

fragmentManager.beginTransaction().apply {

show(showFragment)

//获取其中所有的fragment,其他的fragment进行隐藏

val fragments = fragmentManager.fragments

for (fragment in fragments) {

if (fragment != showFragment) {

hide(fragment)

}

}

}.commit()

在AndroidX中,可以对其进行改进,对于可见的Fragment设置其最大生命周期为onResume,对不可见的Fragment设置最大生命周期为onStart。

// FrameLayout绑定多个Fragment

private fun loadFragmentsTransaction(

@IdRes containerViewId: Int, showPosition: Int,

fragmentManager: FragmentManager, vararg fragments: Fragment) {

if (fragments.isNotEmpty()) {

fragmentManager.beginTransaction().apply {

for (index in fragments.indices) {

val fragment = fragments[index]

add(containerViewId, fragment, fragment.javaClass.name)

// 通过setMaxLifecycle设置最大生命周期

if (showPosition == index) {

setMaxLifecycle(fragment, Lifecycle.State.RESUMED)

} else {

hide(fragment)

setMaxLifecycle(fragment, Lifecycle.State.STARTED)

}

}

}.commit()

} else {

throw IllegalStateException(

"fragments must not empty"

)

}

}

// 控制Fragment的显示/隐藏

private fun showHideFragmentTransaction(fragmentManager: FragmentManager, showFragment: Fragment) {

fragmentManager.beginTransaction().apply {

show(showFragment)

// 对可见的Fragment设置最大生命周期

setMaxLifecycle(showFragment, Lifecycle.State.RESUMED)

//获取其中所有的fragment,其他的fragment进行隐藏

val fragments = fragmentManager.fragments

for (fragment in fragments) {

if (fragment != showFragment) {

hide(fragment)

setMaxLifecycle(fragment, Lifecycle.State.STARTED)

}

}

}.commit()

但测试得到Fragment+Fragment嵌套时,依然会调用不可见Fregment的onResume方法,所以FragmentTransaction模式不能但但只靠onResume判断还要加上isHidden

abstract class LazyXFragment : LogFragment() {

private var isLoaded = false //是否已经加载过数据

override fun onResume() {

super.onResume()

if (!isLoaded && !isHidden) {

lazyInit()

isLoaded = true

}

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

}

abstract fun lazyInit()

}

AndroidX的ViewPager2、ViewPager、FragmentTransaction懒加载

提示:ViewPager的适配器和FragmentTransaction要适配setMaxLifecycle方法。

abstract class LazyXFragment : LogFragment() {

private var isLoaded = false //是否已经加载过数据

override fun onResume() {

super.onResume()

if (!isLoaded && !isHidden) {

lazyInit()

isLoaded = true

}

}

override fun onDestroyView() {

super.onDestroyView()

isLoaded = false

}

abstract fun lazyInit()

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值