J'ai suivi la documentation officielle pour configurer un TabLayout avec ViewPager2. J'ai utilisé le TabLayoutMediator de cette façon pour connecter le TabLayout avec le ViewPager2:
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.setIcon(getTabIcon(position))
tab.text = getTabTitle(position)
}.attach()
Cependant Leak Canary détecte une fuite de mémoire qui semble liée au TabLayout et au TabLayoutMediator. Le journal est le suivant:
2020-05-13 17:57:32.914 D/LeakCanary: ┬───
2020-05-13 17:57:32.914 D/LeakCanary: │ GC Root: Local variable in native code
2020-05-13 17:57:32.914 D/LeakCanary: │
2020-05-13 17:57:32.914 D/LeakCanary: ├─ Android.net.ConnectivityThread instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (PathClassLoader↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ Thread name: 'ConnectivityThread'
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ConnectivityThread.contextClassLoader
2020-05-13 17:57:32.914 D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (ViewDataBinding↓ is not leaking and A ClassLoader is never leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ PathClassLoader.runtimeInternalObjects
2020-05-13 17:57:32.914 D/LeakCanary: ├─ Java.lang.Object[] array
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (ViewDataBinding↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ Object[].[349]
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding class
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking and a class is never leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ static ViewDataBinding.sReferenceQueue
2020-05-13 17:57:32.914 D/LeakCanary: ├─ Java.lang.ref.ReferenceQueue instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ReferenceQueue.head
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding$WeakListener instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ViewDataBinding$WeakListener.mObservable
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding$LiveDataListener instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ViewDataBinding$LiveDataListener.mLifecycleOwner
2020-05-13 17:57:32.914 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.route_info.RouteInfoFragment instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: NO (RouteDashboardFragment↓ is not leaking and Fragment#mFragmentManager is not null)
2020-05-13 17:57:32.915 D/LeakCanary: │ Fragment.mTag=f0
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ RouteInfoFragment.mParentFragment
2020-05-13 17:57:32.915 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardFragment instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: NO (Fragment#mFragmentManager is not null)
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ RouteDashboardFragment.mLifecycleRegistry
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.lifecycle.LifecycleRegistry instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ LifecycleRegistry.mObserverMap
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.Arch.core.internal.FastSafeIterableMap instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ FastSafeIterableMap.mHashMap
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ Java.util.HashMap instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap.table
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ Java.util.HashMap$Node[] array
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap$Node[].[1]
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ Java.util.HashMap$Node instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap$Node.key
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.viewpager2.adapter.FragmentStateAdapter$5 instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ Anonymous class implementing androidx.lifecycle.LifecycleEventObserver
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ FragmentStateAdapter$5.this$0
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardViewPagerAdapter instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ RouteDashboardViewPagerAdapter.mObservable
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ androidx.recyclerview.widget.RecyclerView$AdapterDataObservable instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ RecyclerView$AdapterDataObservable.mObservers
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ Java.util.ArrayList instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ ArrayList.elementData
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ Java.lang.Object[] array
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ Object[].[0]
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.Android.material.tabs.TabLayoutMediator$PagerAdapterObserver instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayoutMediator$PagerAdapterObserver.this$0
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.Android.material.tabs.TabLayoutMediator instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayoutMediator.tabLayout
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.Android.material.tabs.TabLayout instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: YES (View detached and has parent)
2020-05-13 17:57:32.916 D/LeakCanary: │ mContext instance of iclaude.berlinwanderer.features.route.ui.RouteActivity with mDestroyed = false
2020-05-13 17:57:32.916 D/LeakCanary: │ View#mParent is set
2020-05-13 17:57:32.916 D/LeakCanary: │ View#mAttachInfo is null (view detached)
2020-05-13 17:57:32.916 D/LeakCanary: │ View.mID = R.id.tab_layout
2020-05-13 17:57:32.916 D/LeakCanary: │ View.mWindowAttachCount = 1
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayout.mParent
2020-05-13 17:57:32.916 D/LeakCanary: ╰→ androidx.constraintlayout.motion.widget.MotionLayout instance
2020-05-13 17:57:32.916 D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
2020-05-13 17:57:32.916 D/LeakCanary: key = 9c28ffc6-b1ce-4316-b015-c4df278892a1
2020-05-13 17:57:32.916 D/LeakCanary: watchDurationMillis = 36154
2020-05-13 17:57:32.916 D/LeakCanary: retainedDurationMillis = 31130
2020-05-13 17:57:32.916 D/LeakCanary: mContext instance of iclaude.berlinwanderer.features.route.ui.RouteActivity with mDestroyed = false
2020-05-13 17:57:32.917 D/LeakCanary: View#mParent is null
2020-05-13 17:57:32.917 D/LeakCanary: View#mAttachInfo is null (view detached)
2020-05-13 17:57:32.917 D/LeakCanary: View.mID = R.id.ml_main
2020-05-13 17:57:32.917 D/LeakCanary: View.mWindowAttachCount = 1
Quel est le problème? Comment résoudre?
J'ai eu le même problème similaire, vous devez définir l'adaptateur viewPager sur null dans onDestroyView, alors possible si vous utilisez la liaison de données, assurez-vous de définir la liaison sur null. Bonne chance
Votre mContext, exposé par RouteActivity, persiste même après la destruction (ou recréation) de RouteActivity. Cela se produit probablement parce que quelque chose l'utilise. Suivez ce qui utilise mContext et arrêtez cela.