Il componente Navigation Arch potrebbe creare una perdita di memoria falsa positiva?


14

Ho una conoscenza di base delle perdite di memoria e di cosa può causarle. Ecco perché non capisco se ho un problema nel mio codice o è un falso positivo. Non so quale parte del codice dovrei condividere poiché il progetto non è piccolo. Fammi sapere nei commenti e aggiungerò il codice richiesto.

Uso il componente dell'arco di navigazione e seguo il modello MVVM. Ho aggiunto la libreria LeakCanary più avanti nello sviluppo del progetto e ha iniziato immediatamente a darmi avvisi sulle istanze conservate quando navigo tra le schermate.

Il problema si verifica quando aggiungo frammenti allo stack posteriore. Con ogni frammento aggiunto allo stack posteriore aumenta il contatore delle istanze conservate. Quando raggiunge il valore di soglia di 5 LeakCanary scarica l'heap e fornisce il report.

Ma se faccio clic sul pulsante Indietro e torno alle schermate precedenti, il contatore delle istanze conservate diminuisce e alla fine, quando ritorna alla prima schermata, tutte le istanze conservate scompaiono.

Se guardo i rapporti di analisi dell'heap, si dice che CoordinatorLayoutè trapelato il variabile coordinatorLayout che è un riferimento a in xml. Se rimuovo la variabile e tutto il suo utilizzo ed eseguo nuovamente l'app vedo lo stesso problema, ma ora con un'altra variabile che è un riferimento a un'altra vista in XML. Ho provato a rimuovere tutte le visualizzazioni e il loro utilizzo che LeakCanary ha segnalato come perdite. Quando è stato detto che a TextView, che è appena usato per inserire un testo onViewCreatede non usato altrove, ho iniziato a dubitare che ci sia un problema nel mio codice.

Ho analizzato le chiamate del metodo del ciclo di vita in frammenti e ho notato che quando passo alla nuova schermata per il frammento precedente, tutti i metodi fino a includere onDestroyViewvengono chiamati ma non onDestroy. Quando clicco indietro onDestroyviene chiamato il frammento che si trovava sopra lo stack posteriore e il contatore delle istanze mantenute diminuisce.

Ho il sospetto che il componente di navigazione stia mantenendo l'istanza di un frammento quando è nello stack posteriore e LeakCanary lo vede come una perdita.

Risposte:


24

Ecco come funzionano i frammenti sullo stack posteriore (e la navigazione utilizza solo le API dei frammenti esistenti): la vista del frammento viene distrutta, ma il frammento stesso non viene distrutto: vengono mantenuti nello CREATEDstato fino a quando non si preme il pulsante Indietro e si ritorna al frammento (dopodiché onCreateView()verrà chiamato di nuovo e tornerai su RESUMED).

Come per i frammenti: discorso passato, presente e futuro , uno dei cambiamenti futuri in arrivo su Fragments è un'opzione opt in per distruggere i frammenti sul back stack, piuttosto che avere due cicli di vita separati. Questo non è ancora disponibile.

Devi annullare i tuoi riferimenti alle viste in onDestroyViewquanto questo è il segno che la vista non viene più utilizzata dal sistema Fragment e può essere tranquillamente raccolta in modo inutile se non fosse per il tuo riferimento continuo alla Vista.


2
Android View Binding risolve questo problema? Non riesco a trovare alcuna documentazione per stabilire se il riferimento alle viste Visualizza rilegatura (forse l'oggetto di rilegatura stesso) viene automaticamente "annullato" onDestroyViewcon Visualizza rilegatura.
Tim Malseed,

3
@TimMalseed: devi annullare da solo il tuo riferimento all'oggetto vincolante, non c'è nulla di automatico.
ianhanniballake,

1
@Emmanuel: è necessario eliminare il riferimento all'oggetto di rilegatura stesso poiché contiene un riferimento rigido alle viste di proprietà.
ianhanniballake,


1
@Emmanuel - Penso che sarebbe certamente un cambiamento nel comportamento (che potrebbe implicare che si tratti di un flag di opt-in separato), ma avere il LifecycleOwner corretto sarebbe abbastanza informazioni per risolvere una serie intera di problemi di memoria.
ianhanniballake,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.