替换片段时内存泄漏

Memory leak when I replace a Fragment

我刚开始使用 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 上的泄漏警告最终消失了。但我认为这不是解决方案,也没有意义,因为可能会有很多意见。那么避免这种泄漏的解决方案是什么?谢谢。

So I tried to make all views null like below

Eventually leaking warnings on LeakCanary disappeared.

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

But I think this is not a solution and does not make sense because there may be many views. So what's the solution to avoid this leaks?

如果您手动将 View 存储在成员变量中,那是最好的解决方案。您可以使用 findViewById 每次都找到它,但我不推荐它,因为您会因反复遍历视图层次结构而导致性能下降。

您可以使用 Android 开发工具的 View Binding 功能来避免这两个问题。这样一来,您将只需要删除一个 Binding 对象。

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