Утечка памяти с фрагментами - PullRequest
0 голосов
/ 07 октября 2019

Я разрабатываю приложение с одним действием. Внутри есть основной фрагмент и два фрагмента, вот код:

<?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)])

В дополнение к основному фрагменту, встроенный и все последующие также протекают, если вы переключаетесь на них, но если вы возвращаетесь к основному, утечка исчезает,Я понятия не имею, как это исправить. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 08 октября 2019

Основываясь на утечке, мы можем видеть, что MainFragment не протекает, но имеет поле binding, которое имеет ссылку на FragmentMainBindingImpl, который сам ссылается на отдельное представление. Это представление является представлением MainFragment, что означает, что был вызван Fragment.onDestroyView (). Когда вызывается Fragment.onDestroyView (), фрагмент должен отпустить ссылку на представление, т. Е. Для binding должно быть установлено значение null.

...