'Data binding causes memory leak even the binding has been nullified

I've done my research on memory leak when using Data Binding. Every posts said that one should assign null to binding object to resolve this issue. However, it just doesn't work.

I've created two identical Fragments with a single Activity. Each Fragment includes a button which can be used to navigate to one another.

To reproduce this issue, click the button repeatedly, LeakCanary will pop up the memory leak warning. (However, the issue does not occur when clicking the buttons "programmatically")

Repro

enter image description here

LeakCanary

LeakCanary

Code

The following is the code of my Fragments. (Two fragments are identical)

FirstFragment.kt

class FirstFragment : Fragment() {

    private var _binding: FragmentFirstBinding? = null
    val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        _binding = FragmentFirstBinding.inflate(layoutInflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.lifecycleOwner = viewLifecycleOwner
        binding.btnFirst.setOnClickListener {
            findNavController().navigate(R.id.action_to_second)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

fragment_first.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".FirstFragment">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/first_fragment" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/btn_first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="To second" />
    </FrameLayout>
</layout>

SecondFragment.kt

class SecondFragment : Fragment() {

    private var _binding: FragmentSecondBinding? = null
    val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        _binding = FragmentSecondBinding.inflate(layoutInflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.lifecycleOwner = viewLifecycleOwner
        binding.btnSecond.setOnClickListener {
            findNavController().navigate(R.id.action_to_first)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

fragment_second.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".SecondFragment">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/second_fragment" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/btn_second"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="To first" />
    </FrameLayout>
</layout>

I've also created a repo in case someone want to try it out.

Let me know if I can provide any further information. Thanks!



Solution 1:[1]

To all whom may have run into this issue, the developer team of leakcanaray has found the source and marked the leak as known issue.

github.com/square/leakcanary/issues/2341

A related issue can be found on Google issue tracker.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 clement.l