Comprensione del set di FragmentRetainInstance (booleano)


341

A partire dalla documentazione:

public void setRetainInstance (mantenimento booleano)

Controlla se un'istanza di frammento viene mantenuta durante la ricostruzione di attività (ad esempio da una modifica della configurazione). Questo può essere usato solo con frammenti non nello stack posteriore. Se impostato, il ciclo di vita del frammento sarà leggermente diverso quando viene ricreata un'attività:

  • onDestroy () non verrà chiamato (ma lo sarà comunque onDetach (), poiché il frammento viene staccato dalla sua attività corrente).
  • onCreate (Bundle) non verrà chiamato poiché il frammento non viene ricreato.
  • onAttach (Activity) e onActivityCreated (Bundle) verranno comunque chiamati.

Ho alcune domande:

  • Anche il frammento mantiene la sua visione o verrà ricreato in caso di modifica della configurazione? Cosa significa esattamente "trattenuto"?

  • Il frammento verrà distrutto quando l'utente lascia l'attività?

  • Perché non funziona con i frammenti nello stack posteriore?

  • Quali sono i casi d'uso in cui ha senso utilizzare questo metodo?


Risposte:


348

Prima di tutto, controlla il mio post sui frammenti conservati. Potrebbe aiutare

Ora per rispondere alle tue domande:

Il frammento mantiene anche il suo stato di visualizzazione o verrà ricreato in caso di modifica della configurazione: che cosa viene esattamente "conservato"?

Sì, lo Fragmentstato verrà mantenuto per tutta la modifica della configurazione. In particolare, "mantenuto" significa che il frammento non verrà distrutto in caso di modifiche alla configurazione. Cioè, Fragmentverrà mantenuto anche se la modifica della configurazione provoca la Activitydistruzione del sottostante .

Il frammento verrà distrutto quando l'utente lascia l'attività?

Proprio come Activitys, Fragments può essere distrutto dal sistema quando le risorse di memoria sono insufficienti. Il fatto che i tuoi frammenti mantengano il loro stato di istanza attraverso le modifiche alla configurazione non avrà alcun effetto sul fatto che il sistema distruggerà o meno i messaggi di posta elettronica Fragmentuna volta che hai lasciato il file Activity. Se si lascia il Activity(cioè premendo il tasto home), la Fragments può o non può essere distrutta. Se si esce Activitypremendo il pulsante Indietro (quindi, chiamando finish()e distruggendo efficacemente il Activity), verranno distrutti anche tutti Activityi messaggi collegati Fragment.

Perché non funziona con i frammenti nello stack posteriore?

Probabilmente ci sono molte ragioni per cui non è supportato, ma la ragione più ovvia per me è che Activitycontiene un riferimento a FragmentManagere FragmentManagergestisce lo backstack. Cioè, indipendentemente dal fatto che tu scelga di conservare i tuoi Fragmento meno, il Activity(e quindi il FragmentManagerbackstack) verrà distrutto a seguito di una modifica della configurazione. Un altro motivo per cui non potrebbe funzionare è perché le cose potrebbero diventare difficili se entrambi conservati frammenti e frammenti non trattenuto è stato permesso di esistere sulla stessa backstack.

Quali sono i casi d'uso in cui ha senso utilizzare questo metodo?

I frammenti conservati possono essere molto utili per la propagazione delle informazioni sullo stato, in particolare la gestione dei thread, tra istanze di attività. Ad esempio, un frammento può fungere da host per un'istanza di , Threado AsyncTaskgestirne il funzionamento. Vedi il mio post sul blog su questo argomento per ulteriori informazioni.

In generale, lo tratterei allo stesso modo dell'uso onConfigurationChangedcon un Activity... non usarlo come un cerotto solo perché sei troppo pigro per implementare / gestire correttamente un cambio di orientamento. Usalo solo quando è necessario.


37
Gli oggetti di visualizzazione non vengono mantenuti, vengono sempre distrutti in caso di modifiche alla configurazione.
Markus Junginger,

103
Per quanto ne so, se hai setRetainInstance(true), l' Fragmentoggetto java e tutto il suo contenuto non vengono distrutti durante la rotazione, ma la vista viene ricreata. Questo è onCreatedView()chiamato di nuovo. È sostanzialmente il modo in cui avrebbe dovuto funzionare Activitiesda Android 1.0. Non penso che sia "pigro" usarlo, o usarlo non è "corretto". In realtà non riesco a capire perché non sia l'impostazione predefinita o perché mai lo desideri.
Timmmm,

25
Trovo la tua spiegazione per "Perché non funziona con i frammenti nello stack posteriore?" difficile da capire. Ma forse sono stupido :(
HGPB

13
@dierre Un'attività può essere distrutta in molti modi. Ad esempio, se si fa clic su "indietro", l'attività verrà distrutta. Se fai clic su "home", l'attività verrà interrotta e in futuro potrebbe essere distrutta quando la memoria è insufficiente. I messaggi conservati Fragmentvengono mantenuti solo attraverso le modifiche di configurazione, in cui l'attività sottostante deve essere distrutta e ricreata immediatamente. In tutti gli altri casi in cui l'attività viene distrutta, anche i frammenti conservati verranno distrutti.
Alex Lockwood,

3
@AlexLockwood puoi per favore confermare quanto segue: anche se setRetainInstance(true)viene utilizzato, è comunque necessario implementare la propria persistenza ( savedInstanceStateo altrimenti) per essere in grado di gestire tutti gli scenari: ad esempio "chiave home, rotazione, ritorno all'app" ricrea il mio frammento con il costruttore chiama, perdendo tutte le variabili di stato. Ho una AsyncTaskvariabile come membro, ecco perché voglio conservare, ora, se voglio che funzioni, sono costretto a interrompere l'attività, salvare lo stato e riprendere quando l'utente torna. Quindi, tutto sommato, questo è solo un modo rapido per aiutare con la rotazione, ma per il resto inutile in generale.
TWiStErRob,

28

setRetaininstanceè utile solo quando activityviene distrutto e ricreato a causa di una modifica della configurazione perché le istanze vengono salvate durante una chiamata a onRetainNonConfigurationInstance. Cioè, se si ruota il dispositivo, i frammenti conservati rimarranno lì (non vengono distrutti e ricreati.) Ma quando il runtime uccide l'attività per recuperare le risorse, non viene lasciato nulla. Quando premi il pulsante indietro e esci dall'attività, tutto viene distrutto.

Di solito uso questa funzione per salvare l'orientamento cambiando il tempo. Detto che ho scaricato un sacco di bitmap dal server e ognuna è di 1 MB, quando l'utente ruota accidentalmente il suo dispositivo, certamente non voglio fare di nuovo tutto il lavoro di download. Creo Fragmenttrattenendo le mie bitmap e le aggiungo al gestore e chiamo setRetainInstance, tutte le bitmap sono ancora presenti anche se l'orientamento dello schermo cambia.


Crei frammenti "Solo dati" (senza alcun widget) proprio come un supporto per le tue bitmap o anche quei frammenti possono avere widget? Ho letto qualcosa sul pericolo di produrre perdite di memoria quando il frammento contiene qualcosa legato al contesto / Attività ...
hgoebl,

Il framework cancella il mActivityriferimento per te. Ma non so se il runtime eliminerebbe anche i widget nell'istanza del frammento in questo caso. Provalo o immergiti nel codice sorgente.
suitianshi,

Bell'esempio di quando possiamo usare il set Retaininstance
Mu Sa

12

SetRetainInstance (true) consente al tipo di frammento di sopravvivere. I suoi membri verranno mantenuti durante il cambio di configurazione come la rotazione. Ma può ancora essere ucciso quando l'attività viene uccisa in background. Se l'attività di contenimento in background viene interrotta dal sistema, è relativo all'istanza di essere salvata dal sistema che hai gestito correttamente su SaveInstanceState. In altre parole, onSaveInstanceState verrà sempre chiamato. Sebbene onCreateView non verrà chiamato se SetRetainInstance è vero e il frammento / attività non viene ancora ucciso, verrà comunque chiamato se viene ucciso e si tenta di riportarlo indietro.

Ecco alcune analisi dell'attività / frammento di androide che spero possa aiutare. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html


8
Sto sicuramente vedendo onCreateView che viene richiamato di nuovo sul frammento mantenuto quando si ruota lo schermo.
aij,

Questo link è il tuo blog? Dovresti chiarirlo se è così.
Flexo

4

setRetainInstance () - Obsoleto

As Fragments Versione 1.3.0-alpha01

Il metodo setRetainInstance () su Fragments è stato deprecato. Con l'introduzione di ViewModels, gli sviluppatori hanno un'API specifica per il mantenimento dello stato che può essere associata ad attività, frammenti e grafici di navigazione. Ciò consente agli sviluppatori di utilizzare un frammento normale, non conservato e di mantenere separato lo stato specifico che desiderano mantenere, evitando una fonte comune di perdite mantenendo le proprietà utili di una singola creazione e distruzione dello stato conservato (vale a dire, il costruttore del ViewModel e il callback onCleared () che riceve).


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.