Leak Canary 使用 ViewPager2 检测 TabLayout 的内存泄漏 [英] Leak Canary detects memory leaks for TabLayout with ViewPager2
问题描述
我按照官方文档设置了一个带有 ViewPager2 的 TabLayout.我以这种方式使用 TabLayoutMediator 将 TabLayout 与 ViewPager2 连接起来:
I followed the official documentation to setup a TabLayout with ViewPager2. I used the TabLayoutMediator this way to connect the TabLayout with the ViewPager2:
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.setIcon(getTabIcon(position))
tab.text = getTabTitle(position)
}.attach()
但是 Leak Canary 检测到似乎与 TabLayout 和 TabLayoutMediator 相关的内存泄漏.日志如下:
However Leak Canary detects a memory leak that seems related to the TabLayout and the TabLayoutMediator. The log is the following:
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
有什么问题吗?如何解决?
What's the problem? How to solve?
推荐答案
我认为这是一个错误,已在 google 上列出.
I think this is a bug, its listed on google.
https://issuetracker.google.com/issues/151212195https://issuetracker.google.com/issues/154751401
评论中提到的解决方案似乎对我有用.使您的 FragmentStateAdapter
用户成为构造函数
There is a solution mentioned in the comments that seems to be working for me. Make your FragmentStateAdapter
user the constructor
public FragmentStateAdapter(@NonNull FragmentManager fragmentManager,
@NonNull Lifecycle lifecycle) {
从您的容器片段创建适配器,如下所示:
From your container fragment create the adapter as follows:
FragmentManager fm = getChildFragmentManager();
Lifecycle lifecycle = getViewLifecycleOwner().getLifecycle();
fragmentAdapter = new FragmentAdapter(fm, lifecycle);
这篇关于Leak Canary 使用 ViewPager2 检测 TabLayout 的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!