美文网首页
你真的会用 Fragment 吗?

你真的会用 Fragment 吗?

作者: Drew_MyINTYRE | 来源:发表于2022-02-11 21:36 被阅读0次

FragmentManager 使用 Tips

  • 在 activity 中使用 ViewPager,BottomSheetFragment 和 DialogFragment 时,都应使用 getSupportFragmentManager;

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

getSupportFragmentManager 与 activity 关联,可以将其视为 activity 的 FragmentManagergetChildFragmentManagerfragment 关联,可以将其视为 fragment 的 FragmentManager;getParentFragmentManager 情况稍微复杂,正常情况返回的是该 fragment 依附的 activity 的FragmentManager。如果该 fragment 是另一个 fragment 的子 fragment,则返回的是其父 fragment 的 getChildFragmentManager

错误的在 fragment 中使用 activity 的 FragmentManager 会引发内存泄露。 为什么呢?

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

FragmentStateAdapter 和 FragmentPagerAdapter

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

issue 1 刷新 ViewPager 不生效

ViewPager 中的 fragment 是通过 activity 或 fragment 的 FragmentManager 管理的,FragmentManager 包含了 ViewPage 的所有 fragment 的实例,因此,当ViewPager 没有刷新时,它只是 FragmentManager 仍保留的旧 fragment 实例。 您需要找出为什么 FragmentManger 持有 fragment 实例的原因!

issue 2 在 ViewPage 中访问当前 fragment

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

 var fragment: ChildFragment? = null
 override fun setPrimaryItem(container: ViewGroup, position: Int, any: Any) {
   if (getChildFragment() != any) {
      fragment = any as ChildFragment
   }
   super.setPrimaryItem(container, position, any)
  }

  fun getChildFragment(): ChildFragment? = fragment

//use
mAapter.getChildFragment()

add 和 replace 如何选择?

replace 删除现有 fragment 并添加一个新 fragment。 这意味着当您按下返回按钮时,将创建被替换的 fragment,并调用其 onCreateView()。 而 add 保留现有 fragment,并添加一个新fragment,这意味着现有 fragment 将处于活动状态,并且它们不会处于 paused 状态。 因此,按下返回按钮时,现有fragment(添加新fragment之前的fragment)不会调用 onCreateView。 就 fragment 的生命周期事件而言,在 replace 的情况下将调用 onPauseonResumeonCreateView 和其他生命周期事件,在 add 的情况下则不会。

如果不需要重新访问当前 fragment 并且不再需要当前 fragment,请使用replace。 另外,如果您的应用有内存限制,请考虑使用 replace。

observe LiveData 时传入 this 还是 viewLifecycleOwner

androidx fragment 1.2.0 起,添加了新的 Lint 检查,以确保您在 onCreateView()onViewCreated()onActivityCreated() 观察 LiveData 时使用 getViewLifecycleOwner()

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

supportFragmentManager.commit {
    replace(R.id.content, MyFragment.newInstance("Fragment"),
            MyFragment::class.java.simpleName)
    addToBackStack(null)
}

上面那样写不会出现什么问题,但是…

val fragment = supportFragmentManager.findFragmentByTag(tag)

这样获取到的 fragment 可能不是想要的结果。为什么呢?

// 两个 fragment,经过混淆,它们变成
com.mypackage.FragmentA → com.mypackage.c.a
com.mypackage.FragmentB → com.mypackage.c.a.a

如果是 simpleName 呢?

com.mypackage.FragmentA → a
com.mypackage.FragmentB → a

所以在设置 tag 时尽量用全名或者常量。

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

当我们使用 BottomBarNavigation 和 NavigationDrawer 时,通常会看到诸如fragment 重建或多次添加相同 fragment 之类的问题。

在这种情况下,您可以使用 show / hide 而不是 add 或 replace。

返回栈

如果您想在 fragment 的一系列跳转中按返回键返回上一个 fragment,应该在commit transaction 之前调用 addToBackStack 方法。

// 使用该扩展 androidx.fragment:fragment-ktx:1.2.0 以上
parentFragmentManager.commit {
    addToBackStack(null) // 删除 fragment 的时候,仅执行 onDestroyView
    add<SecondFragment>(R.id.content)
}

相关文章

网友评论

      本文标题:你真的会用 Fragment 吗?

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