我正在开发具有单一活动的应用程序。内部有一个主要片段和两个片段,这是代码:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.coreproject.presentation.viewModel.MainViewModel" />
</data>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_normal"
android:onClick="@{viewModel::resetAuth}"
android:text="Reset authorization" />
<Button
android:id="@+id/about_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_normal"
android:onClick="@{viewModel::goToAbout}"
android:text="About" />
<fragment
class="com.example.services.presentation.view.PopularServiceListFragmentWidget"
android:id="@+id/widget_popular_services"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_normal"/>
<fragment
class="com.example.services.presentation.view.CategoryListFragmentWidget"
android:id="@+id/widget_categories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_normal"
android:layout_marginBottom="@dimen/padding_big"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</layout>
我可以从这里转到另一个片段,当我这样做时,会发生内存泄漏。这是堆栈跟踪:
LeakingInstance(referenceKey=c4b8a77a-e8c0-4e6a-937d-d14422c9a616, referenceName=,
instanceClassName=androidx.core.widget.NestedScrollView, watchDurationMillis=-515750270,
exclusionStatus=null, leakTrace=
D/LeakCanary: ┬
D/LeakCanary: ├─ android.os.HandlerThread
D/LeakCanary: │ Leaking: NO (it's a GC root)
D/LeakCanary: │ Thread name: 'LeakCanary-Heap-Dump'
D/LeakCanary: │ ↓ thread HandlerThread.contextClassLoader
D/LeakCanary: ├─ dalvik.system.PathClassLoader
D/LeakCanary: │ Leaking: NO (Object[]↓ is not leaking and Classloader never leaking)
D/LeakCanary: │ ↓ PathClassLoader.runtimeInternalObjects
D/LeakCanary: ├─ java.lang.Object[]
D/LeakCanary: │ Leaking: NO (Glide↓ is not leaking)
D/LeakCanary: │ ↓ array Object[].[694]
D/LeakCanary: ├─ com.bumptech.glide.Glide
D/LeakCanary: │ Leaking: NO (Glide↓ is not leaking and a class is never leaking)
D/LeakCanary: │ ↓ static Glide.glide
D/LeakCanary: ├─ com.bumptech.glide.Glide
D/LeakCanary: │ Leaking: NO (ArrayList↓ is not leaking)
D/LeakCanary: │ ↓ Glide.managers
D/LeakCanary: ├─ java.util.ArrayList
D/LeakCanary: │ Leaking: NO (Object[]↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList.elementData
D/LeakCanary: ├─ java.lang.Object[]
D/LeakCanary: │ Leaking: NO (RequestManager↓ is not leaking)
D/LeakCanary: │ ↓ array Object[].[2]
D/LeakCanary: ├─ com.bumptech.glide.RequestManager
D/LeakCanary: │ Leaking: NO (SupportRequestManagerFragment$SupportFragmentRequestManagerTreeNode↓ is not leaking)
D/LeakCanary: │ ↓ RequestManager.treeNode
D/LeakCanary: ├─ com.bumptech.glide.manager.SupportRequestManagerFragment$SupportFragmentRequestManagerTreeNode
D/LeakCanary: │ Leaking: NO (SupportRequestManagerFragment↓ is not leaking)
D/LeakCanary: │ ↓ SupportRequestManagerFragment$SupportFragmentRequestManagerTreeNode.this$0
D/LeakCanary: ├─ com.bumptech.glide.manager.SupportRequestManagerFragment
D/LeakCanary: │ Leaking: NO (MainFragment↓ is not leaking and SupportRequestManagerFragment#mFragmentManager is not null)
D/LeakCanary: │ ↓ SupportRequestManagerFragment.mParentFragment
D/LeakCanary: ├─ com.example.coreproject.presentation.view.MainFragment
D/LeakCanary: │ Leaking: NO (MainFragment#mFragmentManager is not null)
D/LeakCanary: │ ↓ MainFragment.binding
D/LeakCanary: │ ~~~~~~~
D/LeakCanary: ├─ com.example.coreproject.databinding.FragmentMainBindingImpl
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ ↓ FragmentMainBindingImpl.mRoot
D/LeakCanary: │ ~~~~~
D/LeakCanary: ╰→ androidx.core.widget.NestedScrollView
D/LeakCanary: Leaking: YES (RefWatcher was watching this)
D/LeakCanary: , retainedHeapSize=null)])
除了主片段,如果切换到内置片段和所有后续片段,它们也会泄漏,但是如果返回到主要片段,则泄漏将消失。我不知道该如何解决。任何帮助表示赞赏。
基于泄漏跟踪,我们可以看到MainFragment没有泄漏,但是它有一个binding
字段,该字段引用了FragmentMainBindingImpl,而FragmentMainBindingImpl本身引用了一个分离的视图。该视图是MainFragment的视图,这意味着调用了Fragment.onDestroyView()。调用Fragment.onDestroyView()时,片段应放弃对视图的引用,即binding
应设置为null。