【背上Jetpack之Fragment】你真的会用Fragment吗?Fragment常见问题以及androidx下Fragment的使用新姿势

本文详细探讨了Android Jetpack中的Fragment常见问题,如getSupportFragmentManager的使用,FragmentStateAdapter与FragmentPagerAdapter的区别,add与replace的选择,以及LiveData的观察策略。此外,还介绍了Fragment的新特性,如fragment-ktx的扩展函数,FragmentFactory的使用,Fragment返回键拦截,以及Fragment与Activity的通信等,帮助开发者更好地理解和运用Fragment。

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

Android Jetpack 组件中,fragment作为视图控制器之一占有很重要的位置。但由于其bug众多,暗坑无数,以至于 Square 有这样一篇博客:Advocating Against Android Fragments。github上的 Fragmentation 有着 9.4k 的star。

而现在,androidx fragment 稳定版已来到 1.2.2,让我们总结一下fragment有哪些常见问题以及有哪些使用fragment的新姿势

Fragment 常见的问题

  • getSupportFragmentManager , getParentFragmentManager 和 getChildFragmentManager

  • FragmentStateAdapter 和 FragmentPagerAdapter

  • add 和 replace

  • observe LiveData时传入 this 还是 viewLifecycleOwner

  • 使用 simpleName 作为 fragment 的 tag 有何风险?

  • 在 BottomBarNavigation 和 drawer 中如何使用Fragment多次添加?

  • 返回栈

getSupportFragmentManager , getParentFragmentManager和getChildFragmentManager

FragmentManagerandroidx.fragment.app(已弃用的不考虑)下的抽象类,创建用于 添加,移除,替换 fragment 的事务(transaction

首先要确认一件事,getSupportFragmentManager()FragmentActivity下的方法

getParentFragmentManagergetChildFragmentManagerandroidx.fragment.app.Fragment 下的方法,

其中 androidx.fragment 1.2.0getFragmentManagerrequireFragmentManager 已弃用

明确了这件事,接下来的就很清晰了

  • getSupportFragmentManageractivity关联,可以将其视为 activityFragmentManager
  • getChildFragmentManagerfragment关联,可以将其视为fragmentFragmentManager
  • getParentFragmentManager情况稍微复杂,正常情况返回的是该fragment 依附的activityFragmentManager。如果该fragment是另一个fragment 的子 fragment,则返回的是其父fragmentgetChildFragmentManager

如果这么说还不明白的话,我们可以做一个实践。

创建一个 activity,一个父fragment ,一个子fragment

// activity
class MyActivity : AppCompatActivity(R.layout.activity_main) {
   
    override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        supportFragmentManager.commit {
   
            add<ParentFragment>(R.id.content)
        }
        Log.i("MyActivity", "supportFragmentManager $supportFragmentManager")
    }
}

class ParentFragment : Fragment(R.layout.fragment_parent) {
   
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   
        super.onViewCreated(view, savedInstanceState)
        childFragmentManager.commit {
   
            add<ChildFragment>(R.id.content)
        }
        Log.i("ParentFragment", "parentFragmentManager $parentFragmentManager")
        Log.i("ParentFragment", "childFragmentManager $childFragmentManager")
    }
}

class ChildFragment : Fragment(R.layout.fragment_child) {
   
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   
        super.onViewCreated(view, savedInstanceState)
        Log.i("ChildFragment", "parentFragmentManager $parentFragmentManager")
        Log.i("ChildFragment", "childFragmentManager $childFragmentManager")
    }
}
//log
I/MyActivity: supportFragmentManager FragmentManager{825dcef in HostCallbacks{14a13fc}}}
I/ParentFragment: parentFragmentManager FragmentManager{825dcef in HostCallbacks{14a13fc}}}
I/ParentFragment: childFragmentManager FragmentManager{df5de83 in ParentFragment{7cdd800}}}
I/ChildFragment: parentFragmentManager FragmentManager{df5de83 in ParentFragment{7cdd800}}}
I/ChildFragment: childFragmentManager FragmentManager{aba9afb in ChildFragment{5cea718}}}

因此

  • activity 中使用 ViewPagerBottomSheetFragmentDialogFragment 时,都应使用 getSupportFragmentManager

  • fragment 中使用 ViewPager 时应该使用getChildFragmentManager

错误的在 fragment 中使用 activityFragmentManager 会引发内存泄露。 为什么呢?假如您的fragment中有一些依靠 ViewPager 管理的子 fragment,并且所有这些 fragment 都在 activity 中,因为您使用的是activityFragmentManager 。 现在,如果关闭您的父fragment,它将被关闭,但不会被销毁,因为所有子fragment都处于活动状态,并且它们仍在内存中,从而导致泄漏。 它不仅会泄漏父fragment,还会泄漏所有子fragment,因为它们都无法从堆内存中清除。

FragmentStateAdapter 和 FragmentPagerAdapter

FragmentPagerAdapter将整个 fragment存储在内存中,如果ViewPager中使用了大量 fragment,则可能导致内存开销增加。 FragmentStatePagerAdapter仅存储片段的savedInstanceState,并在失去焦点时销毁所有 fragment

让我们看看常见的两个问题

1. 刷新ViewPager不生效

ViewPager 中的 fragment 是通过 activityfragmentFragmentManager 管理的,FragmentManager 包含了viewpager的所有fragment的实例

因此,当ViewPager没有刷新时,它只是FragmentManager仍保留的旧 fragment 实例。 您需要找出为什么FragmentManger持有fragment实例的原因。

2. 在Viewpager中访问当前fragment

这也是我们遇到的一个非常普遍的问题。 如果遇到这种情况,我们一般在 adapter 内部创建 fragment 的数组列表,或者尝试使用某些标签访问fragment。 不过还有另一种选择。 FragmentStateAdapterFragmentPagerAdapter都提供方法setPrimaryItem。 可以用来设置当前fragment,如下所示:

  var fragment: ChildFragment? = null
  override fun setPrimaryItem(container: ViewGroup
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值