Android 在片段中保留对视图的引用会导致内存泄漏吗?

Android 在片段中保留对视图的引用会导致内存泄漏吗?,android,android-fragments,Android,Android Fragments,有人告诉我以下内容,但我有点困惑。 请问,您能确认还是质疑它? (通过setRetainInstance() 目前,在片段中初始化视图是一种常见做法,如下所示: private lateinit var myTextView: TextView fun onViewCreated(view: View, bundle: Bundle) {      ...      myTextView = view.findViewById(R.id.myTextViewId)      ...

有人告诉我以下内容,但我有点困惑。

请问,您能确认还是质疑它?

(通过
setRetainInstance()


目前,在片段中初始化视图是一种常见做法,如下所示:

private lateinit var myTextView: TextView

fun onViewCreated(view: View, bundle: Bundle) {

     ...

     myTextView = view.findViewById(R.id.myTextViewId)

     ...

}
我们永远不会使这个属性无效。虽然这是一种常见的做法,但它会导致内存泄漏

这方面的背景:

比如说,
FragmentA
引用了它的
视图的子视图,作为一个实例字段。
FragmentManager使用特定的FragmentTransaction执行从片段A到B的导航。根据事务的类型,管理器可能只想终止
视图
,但仍然保留
FragmentA
的实例(请参见下面的生命周期部分,其中说明“片段从后堆栈返回布局”)。当用户从
FragmentB
导航回
FragmentA
时,
FragmentA
的前一个实例将被带到前面,但会创建一个新的
视图


问题是,如果我们在lateinit属性中将实例保留在视图中,并且从未清除对它的引用,则视图无法完全销毁,从而导致内存泄漏。

有一个名为
onDestroyView
的片段生命周期方法,您应该覆盖该方法以释放对视图的任何引用

通常,如果您的
片段
被永久添加到
活动
中,并且它不会被删除,则只应使用
lateinit var
查看引用


通过自动清除onDestroyView中的视图缓存已经解决了这个问题,我不认为有直接的官方答案,但答案在文档中,可以很容易地证明。如果您检查并描述方法,它会说:

  • 调用
    onDestroyView
    后,将分离布局,下次碎片附着时,将重新创建视图
  • 片段实际上可以从后堆栈返回,在本例中调用
    onCreateView
  • 这基本上意味着,如果在片段位于后堆栈中时在片段实例中保留任何视图引用,则可以防止这些视图被垃圾收集

    如果您仍然不确定,可以查看AOSP的源代码。例如,在
    onDestroyView()
    中将所有视图引用都设置为null

    此外,很容易证明存在内存泄漏。只需使用图像视图创建一个片段,该视图将显示完整大小的图像。在片段中保留一个引用,并使用片段事务导航到另一个片段。然后点击
    强制垃圾收集
    按钮,使用该工具创建一个堆转储,您将看到片段实际上持有图像视图和图像本身,阻止它们被收集。如果重复相同的步骤,但在
    onDestroyView()
    中将引用设置为null,您将看到片段的保留大小要小得多,并且堆中不再存在
    ImageView
    实例。

    Edit2 间接官方信息:

    • 和的方法表明,如果没有明确说明,则使用保存状态将
      片段添加到backstack

    • 方法表明,
      Fragment
      可以在方向更改和其他
      活动
      娱乐之间保存其状态-这意味着
      FragmentManager
      相对独立于
      活动
      的生命周期存在,即使
      活动
      被破坏,也可以存储
      Fragment
      状态。

    • 描述…的一句小评论

      在内部,在保存视图的状态之后,但在将其从其父视图中删除之前,会调用它

    它指示保存
    片段
    状态的确切时间

    所有这些点几乎明确地组合在一起表示存在
    片段
    视图的状态,并且它存储在导航事件之间的内存中

    编辑2结束 第一个问题是你的问题

    你说你提供的代码是在片段中初始化视图的一种常见做法。这根本不是一种常见做法。这是谷歌只在其示例和示例中使用的一种陈旧过时的方式。虽然对于示例来说已经足够了,但对生产来说并不好

    • 谷歌目前针对Kotlin的官方标准之一是通过初始化片段或活动中的视图。谷歌甚至在其现代样本和示例中使用这种方法。有一种称为
      clearFindViewByIdCache()
      的方法,可以在需要时消除所有强合成引用(最常见于
      onDestroyView

    • 第二个标准是通过
      、布局xml文件中的
      标记和代码中的
      ViewModel
      使用Android数据绑定。它既适用于Kotlin,也适用于Java,非常简单明了。这样做的原因之一是在使用旧的“标准方式”时消除内存泄漏,使其易于保留配置更改的状态,并统一现代UI层实现的方法。要完全消除可能的内存泄漏,您必须在
      onDestroyView
      中取消绑定。如果实现良好,它可以处理所有现成的内容,包括内存泄漏(没有),在配置更改时保留视图状态,通过
      LivaData
      使用网络或数据库中的相关数据更新UI,与UI的一般通信,处理功能等。目前,它与JetPack的其他功能一起是

    • 还有第三种半官方的方法-使用。如果实现得好,它也能够处理