【问题标题】:Memory leak when I replace a Fragment更换片段时内存泄漏
【发布时间】:2020-05-12 04:31:08
【问题描述】:

我刚刚开始使用 LeakCanary,当我更换 Fragment 时,每次泄漏都会增加。这是 LeakCanary 报告:

android.widget.LinearLayout instance
​     Leaking: YES (ObjectWatcher was watching this because com.home.app1.PostFragment received Fragment#onDestroyView() callback 
     (references to its views should be cleared to prevent leaks))

这是我的片段替换代码:

public void change(Fragment fragment) {

    ((FragmentActivity) context).getSupportFragmentManager().beginTransaction()

            .replace(R.id.frameLayout, fragment, "fragment")
            .setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
            .addToBackStack(null)
            .commit();
}

所以我研究了 SO,有人说必须在onDestroyView 中清除视图。然后我在onDestroyView:fragmentView=null; 中尝试了这个,但没有任何改变。也试过这个:

if (view.getParent() != null) {
        ((ViewGroup) view.getParent()).removeView(view);
    }

但还是没有任何改变。所以我试图让所有视图都为空,如下所示:

   @Override
   public void onDestroyView() {
    super.onDestroyView();
    backButton=null;
    swipeLayout=null;
    imageView=null; ...etc.
   }

LeakCanary 上的泄漏警告最终消失了。但我认为这不是一个解决方案,没有意义,因为可能有很多意见。那么避免这种泄漏的解决方案是什么?谢谢。

【问题讨论】:

  • 请添加您的泄漏跟踪

标签: java android android-fragments memory-leaks leakcanary


【解决方案1】:

所以我尝试让所有视图都为空,如下所示

LeakCanary 上的泄漏警告最终消失了。

您找到了解决方案 - 在 View 引用(您的 backButtonswipeLayoutimageView 等)被删除并应该被销毁 (onDestroyView) 之后,您已经找到了解决方案。由于持有对它们的引用会阻止它们被垃圾回收,这就是内存泄漏。

但我认为这不是一个解决方案,也没有意义,因为可能存在 很多意见。那么避免这种泄漏的解决方案是什么?

如果您手动将Views 存储在成员变量中,这是最好的解决方案。您可以每次都使用findViewById 来查找它,但我不建议您这样做,因为重复遍历视图层次结构会降低性能。

您可以通过使用 Android 开发工具的View Binding 功能来避免这两个问题。这样一来,您只需摆脱一个 Binding 对象。

您还可以使用 Butter Knife 为您管理视图变量 - 请参阅该页面上提到的 unbinder.unbind(); 模式。

【讨论】:

  • 我理解你的建议。但是有很多代码,我没有太多时间做项目。所以我现在不能替换所有findViewById 方法。那么在这种情况下我应该继续使用第一个解决方案(null out)吗?
  • 如果你的时间有限,这可能是最少的工作,我想,是的。
  • 我认为这并不重要。为了与其他生命周期回调保持一致,我通常会这样做。
猜你喜欢
  • 2013-11-30
  • 2015-07-20
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 2019-12-22
  • 1970-01-01
  • 2020-02-15
相关资源
最近更新 更多