【问题标题】:A reference to a retained fragment in a UI fragment. How can the UI fragment be deleted from memory after I rotate the screen?对 UI 片段中保留的片段的引用。旋转屏幕后如何从内存中删除 UI 片段?
【发布时间】:2017-02-14 18:27:09
【问题描述】:

我正在阅读FragmentRetainInstance sample. 在UiFragment 中有变量RetainedFragment mWorkFragment。那么旋转屏幕后如何从内存中删除UiFragment?据我了解,mWorkFragment 是指在屏幕旋转和其他配置更改中仍然存在的东西。

更新 #1

我旋转屏幕并按下 Initiate GC,然后按下 Dump heap。我看到UiFragment 实例的数量是 1。为什么?我希望看到当前方向的 2:1 和上一个方向的 1。

启动 GC:

堆转储:

【问题讨论】:

  • UiFragment 不保留。如果保留,则在重新创建宿主 Activity 时不会重新创建它,这就是 Fragment#setRetainInstance(...) 的工作原理。所以,在你旋转屏幕并初始化一个 gc 之后,之前的 UiFragment 实例应该被垃圾收集。
  • 如何从内存中删除 UiFragment - GC 将从 GC 根(该 UiFragment 实例不是)开始,然后遍历其引用(依此类推) 查看仍然需要哪些对象。所以 mWorkFragment 引用并不重要,因为没有一个对象长期持有对 UiFragment 实例的引用来保持它的活动。
  • @Luksprog,据我从您的评论中了解到,GC 从根(可能是 Application 类)开始遍历对象,然后确定 UiFragment 无法访问(a 之后没有引用配置更改)。所以可以删除。 UiFragment 是不可达子树的根,mWorkFragment 是 UiFragment 的孩子。如果根不可访问,则其所有子节点均不可访问。对吗?
  • 你是对的。如果您想查看内存泄漏,在上面的示例中,在 Activity 的 onCreate() 中放置一个断点,然后更改 RetainedFragment 以删除 onDetach() 中的 mProgressBar = null; 行。调试应用程序,第一次遇到断点时只需继续应用程序(尚未创建任何片段),然后旋转手机。您将在 onCreate() 中再次遇到断点,此时如果您查看保留的片段实例,您会看到 mProgressBar 不为空,并且它会泄漏先前的活动,直到达到 onActivityCreated()。
  • @Luksprog,请结合你的cmets并写一个答案,我会接受它

标签: android android-fragments memory-management screen-rotation


【解决方案1】:

正如我在评论中所说,您链接到的示例中的 UiFragment 没有泄露。它确实包含对 RetainedFragment 的引用,该引用在配置更改后仍然存在,但该引用无关紧要。 GC 将从 GC 根开始,并从那里遍历在对象内部找到的引用之后的对象。由于 UiFragment 不是从存在的东西(如 RetainedFragment)中引用的,因此它将位于活动对象的层次结构之外,并且有资格进行垃圾回收。

如果您想查看内存泄漏,请在您链接到的示例中,从 RetainedFragment 的 onDetach() 回调中删除 mProgressBar = null; 行。通过此更改,RetainedFragment 将持有对 UiFragment 的引用(实际上是旧 Activity 及其所有数据),使旧 Context 实例保持活动状态,至少在调用 RetainedFragment 的 onActivityCreated() 回调之前(在 onActivityCreated 内() mProgressBar 将被清除并指向恢复的 UiFragment 的 ProgressBar)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多