Search code examples
javaandroidandroid-activityleakcanary

Is there a reason for why AccessibilityManager.sInstance would cause a memory leak?


I have an activity that contains a fragment. Running Leak Canary, I see that the activity has a memory leak.

I have commented out all the code from activity and fragment to where the activity is only displaying the fragment and the fragment has an empty xml layout. I have no accessibility in either file or within the xml.

* AccessibilityManager$1.!(this$0)! (anonymous subclass of android.view.accessibility.IAccessibilityManagerClient$Stub)
* ↳ AccessibilityManager.!(mTouchExplorationStateChangeListeners)!
* ↳ CopyOnWriteArrayList.!(elements)!
* ↳ array Object[].!([2])!
* ↳ AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper.!(mListener)!
* ↳ BaseTransientBottomBar$SnackbarBaseLayout$1.!(this$0)! (anonymous implementation of android.support.v4.view.accessibility.AccessibilityManagerCompat$TouchExplorationStateChangeListener)
* ↳ Snackbar$SnackbarLayout.mContext
* ↳ ContextThemeWrapper.mBase
* ↳ MessagesActivity

Solution

  • OK, I actually got it figured out. This is a memory leak in Snackbar and here is how it can be reproduced: https://github.com/GC-Xi/SnackbarBug

    Way to reproduce

    1. Create a Snackbar and reference it in an Activity
    2. Don't call Snackbar.show()
    3. Open and close the Activity
    4. Notice that the Activity is not garbage collected because snackbar has a reference to it

    Cause

    The SnackbarBaseLayout calls addTouchExplorationStateChangeListener() in constructor and removeTouchExplorationStateChangeListener() in onDetachedFromWindow(). Where the addTouchExplorationStateChangeListener() probably should be called from onAttachedToWindow() because the SnackbarBaseLayout is not attached to window unless Snackbar.show() is called.

    Solution 1

    Update to AndroidX and use com.google.android.material.snackbar.Snackbar instead. https://github.com/GC-Xi/SnackbarBug/tree/solution1

    Solution 2

    Do not create the Snackbar unless you are ready to show it. https://github.com/GC-Xi/SnackbarBug/tree/solution2