Leak Canary通过ViewPager2检测TabLayout的内存泄漏。

问题描述 投票:0回答:1

我按照官方文档设置了一个TabLayout与ViewPager2。我用TabLayoutMediator这种方式来连接TabLayout与ViewPager2。

TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
        tab.setIcon(getTabIcon(position))
        tab.text = getTabTitle(position)
    }.attach()

然而Leak Canary检测到了一个内存泄漏,似乎与TabLayout和TabLayoutMediator有关。日志如下。

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

问题是什么?如何解决?

android memory-leaks android-tablayout leakcanary
1个回答
3
投票

我认为这是一个bug,它在谷歌上列出。

https:/issuetracker.google.comissues151212195。https:/issuetracker.google.comissues154751401

评论中提到的一个解决方案,似乎对我有用。让你的 FragmentStateAdapter 用户

 public FragmentStateAdapter(@NonNull FragmentManager fragmentManager,
            @NonNull Lifecycle lifecycle) {

从你的容器片段创建适配器,如下所示。

FragmentManager fm = getChildFragmentManager();
Lifecycle lifecycle = getViewLifecycleOwner().getLifecycle();
fragmentAdapter = new FragmentAdapter(fm, lifecycle);

1
投票

我有同样的问题,你需要在onDestroyView里面把viewPager适配器设置为null,然后如果你使用databinding,确保你把绑定设置为null。好运


0
投票

你的mContext被RouteActivity暴露,即使在RouteActivity被销毁(或重新创建)之后,它仍然在附近徘徊。发生这种情况可能是因为有东西在使用它。追踪使用mContext的东西,并阻止它。

© www.soinside.com 2019 - 2024. All rights reserved.