Best practice to access a Activity View from multiples Fragments and avoid memory leaks

I have a FAB in the main activity and more than 20 fragments access it, changing the icon and the onClickListener.

So i created a extension function for Fragments, the problem i found is that it's leaking memory using this method.

fun Fragment.setupFab(showFab: Boolean = false,
                 @DrawableRes fabIcon: Int = R.drawable.ic_baseline_add_24,
                 fabListener: View.OnClickListener? = null
    (requireActivity() as MainActivity)
    .apply {
        if (showFab) {
            setImageDrawable(ContextCompat.getDrawable(context, fabIcon))
        } else hide() 

So i created an interface that MainActivity extends:

interface FabListener{
    fun setupFab(showFab: Boolean = false,
                @DrawableRes fabIcon: Int = R.drawable.ic_baseline_add_24,
                fabListener: View.OnClickListener? = null)

And then from my fragments i use:

(requireActivity() as FabListener).setupFab(showFab = false){
    //do stuff

But it keeps leaking memory.

How can i solve this or what is the best way to do this?

Would it be best if i create a BottomAppBar and FAB inside each fragment? But this seems a waste to inflate the same think over and over again for each fragment.

Leak canary log:

├─ com.puntogris.blint.ui.main.MainActivity instance
│    Leaking: NO (FloatingActionButton↓ is not leaking and 
│    is false)
│    mApplication instance of com.puntogris.blint.di.App
│    mBase instance of         
│    ↓ BaseActivity._binding
├─ com.puntogris.blint.databinding.ActivityMainBindingImpl     
│    Leaking: NO (FloatingActionButton↓ is not leaking)
│    ↓ ActivityMainBinding.mainFab
│  instance
│    Leaking: NO (View attached)
│    View is part of a window view hierarchy
│    View.mAttachInfo is not null (view attached)
│    View.mID =
│    View.mWindowAttachCount = 1
│    mContext instance of 
     com.puntogris.blint.ui.main.MainActivity with
│    mDestroyed = false
│    ↓ View.mListenerInfo
│           ~~~~~~~~~~~~~
├─ android.view.View$ListenerInfo instance
│    Leaking: UNKNOWN
│    Retaining 8,7 kB in 318 objects
│    ↓ View$ListenerInfo.mOnClickListener
│                        ~~~~~~~~~~~~~~~~
├─ com.puntogris.blint.ui.product.manage.
│  -$$Lambda$ManageProductsFragment$2GI1C37xvlkTJomTwGgPILZJDyM     
│    Leaking: UNKNOWN
│    Retaining 8,6 kB in 315 objects
│    ↓     

╰→ com.puntogris.blint.ui.product
   .manage.ManageProductsFragment instance
Leaking: YES (ObjectWatcher was watching this because com.puntogris.blint.ui.product.manage.ManageProductsFragment received 
callback and Fragment#mFragmentManager is null)
Retaining 8,6 kB in 314 objects
key = c3306747-0b3c-4334-84de-65c4d6eea601
watchDurationMillis = 9493
retainedDurationMillis = 4493
componentContext instance of
ViewComponentManager$FragmentContextWrapper, wrapping activity 
puntogris.blint.ui.main.MainActivity with mDestroyed = false

Read more here:

Content Attribution

This content was originally published by Joaco at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: