Könnte die Navigationsbogenkomponente einen falsch positiven Speicherverlust verursachen?

14

Ich habe Grundkenntnisse über Speicherlecks und deren Ursachen. Deshalb verstehe ich nicht, ob ich ein Problem in meinem Code habe oder ob es falsch positiv ist. Ich weiß nicht, welchen Teil des Codes ich teilen soll, da das Projekt nicht klein ist. Aber lassen Sie es mich einfach in den Kommentaren wissen und ich werde den erforderlichen Code hinzufügen.

Ich benutze die Navigationsbogenkomponente und folge dem MVVM-Muster. Ich habe die LeakCanary-Bibliothek später in der Projektentwicklung hinzugefügt und sofort Warnungen vor beibehaltenen Instanzen erhalten, wenn ich zwischen Bildschirmen navigiere.

Das Problem tritt auf, wenn ich dem Backstack Fragmente hinzufüge. Mit jedem hinzugefügten Fragment zum Backstack erhöht sich der Zähler der beibehaltenen Instanzen. Wenn der Schwellenwert von 5 erreicht ist, gibt LeakCanary den Heap aus und gibt einen Bericht aus.

Wenn ich jedoch auf die Schaltfläche "Zurück" klicke und zu den vorherigen Bildschirmen zurückkehre, verringert sich der Zähler der beibehaltenen Instanzen, und wenn ich zum ersten Bildschirm zurückkehre, verschwinden schließlich alle beibehaltenen Instanzen.

Wenn ich mir Heap-Analyseberichte ansehe, heißt es, dass die Variable KoordinatorLayout, die auf die CoordinatorLayoutXML-Datei verweist, durchgesickert ist. Wenn ich die Variable und ihre gesamte Verwendung entferne und die App erneut ausführe, sehe ich dasselbe Problem, aber jetzt mit einer anderen Variablen, die auf eine andere Ansicht in XML verweist. Ich habe versucht, alle Ansichten und deren Verwendung zu entfernen, die LeakCanary als undicht gemeldet hat. Als es hieß, dass a TextView, das nur zum Einfügen eines Textes onViewCreatedverwendet wird und nirgendwo anders verwendet wird, undicht ist, begann ich zu bezweifeln, dass es ein Problem in meinem Code gibt.

Ich habe die Aufrufe der Lebenszyklusmethode in Fragmenten analysiert und festgestellt, dass beim Navigieren zum neuen Bildschirm für das vorherige Fragment alle Methoden bis einschließlich onDestroyViewaufgerufen werden, jedoch nicht onDestroy. Wenn ich zurückklicke, onDestroywird für Fragment aufgerufen, das sich oben auf dem Backstack befand und der Zähler für beibehaltene Instanzen abnimmt.

Ich vermute, dass die Navigationskomponente die Instanz eines Fragments behält, wenn es sich im Backstack befindet, und LeakCanary es als Leck ansieht.

Marat
quelle

Antworten:

24

So funktionieren Fragmente auf dem Backstack (und Navigation verwendet nur die vorhandenen Fragment-APIs): Die Ansicht des Fragments wird zerstört, aber das Fragment selbst wird nicht zerstört - sie bleiben im CREATEDStatus, bis Sie auf die Schaltfläche "Zurück" klicken und zum Fragment zurückkehren (Danach onCreateView()wird erneut aufgerufen und Sie kehren zurück zu RESUMED).

Gemäß den Vorträgen zu Fragmenten: Vergangenheit, Gegenwart und Zukunft besteht eine der zukünftigen Änderungen bei Fragmenten darin, dass Fragmente auf dem Rückstapel zerstört werden können, anstatt zwei separate Lebenszyklen zu haben. Dies ist noch nicht verfügbar.

Sie müssen Ihre Verweise auf die Ansichten in null auf Null setzen, onDestroyViewda dies das Zeichen dafür ist, dass die Ansicht nicht mehr vom Fragment-System verwendet wird und sicher Müll gesammelt werden kann, wenn Sie nicht weiterhin auf die Ansicht verweisen.

ianhanniballake
quelle
2
Behebt Android View Binding dieses Problem? Ich kann keine Dokumentation darüber finden, ob der Verweis auf View Binding-Ansichten (möglicherweise das Bindungsobjekt selbst) onDestroyViewmit View Binding automatisch auf Null gesetzt wird .
Tim Malseed
3
@TimMalseed - Sie müssen Ihren Verweis auf das Bindungsobjekt selbst auf Null setzen, da ist nichts Automatisches los.
Ianhanniballake
1
@Emmanuel - Sie müssen Ihren Verweis auf das Bindungsobjekt selbst löschen, da dieser einen harten Verweis auf die Ansichten enthält, die es besitzt.
Ianhanniballake
1
@Emmanuel - Sie können jederzeit eine Funktionsanfrage stellen !
Ianhanniballake
1
@Emmanuel - Ich denke, es wäre sicherlich eine Änderung des Verhaltens (was bedeuten könnte, dass es sich um ein separates Opt-In-Flag handelt), aber der richtige LifecycleOwner würde ausreichen, um eine ganze Reihe von Speicherproblemen zu beheben.
Ianhanniballake