È questo il modo giusto per ripulire lo stack posteriore di frammenti quando si lascia uno stack nidificato?


130

Sto usando la libreria di compatibilità Android per implementare frammenti e ho esteso l'esempio di layout in modo che un frammento contenga un pulsante che spara un altro frammento.

Nel riquadro di selezione sulla sinistra ho 5 voci selezionabili - A B C D E.

Ognuno carica un frammento (via FragmentTransaction:replace) nel riquadro dei dettagli -a b c d e

Ora ho esteso il frammento eper contenere un pulsante che carica un altro frammento e1anche nel riquadro dei dettagli. L'ho fatto sul emetodo onClick del frammento come segue:

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

Se faccio le seguenti selezioni:

E - e - e1 - D - E

Quindi il frammento si etrova nel riquadro dei dettagli. Questo va bene e quello che voglio. Tuttavia, se premo il backpulsante a questo punto non fa nulla. Devo fare clic due volte perché e1è ancora in pila. Inoltre, dopo aver fatto clic su, ho ricevuto un'eccezione puntatore null in onCreateView:

Per "risolvere" questo problema ho aggiunto quanto segue ogni volta che A B C D Eè selezionato:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}

Ti stai solo chiedendo se questa è la soluzione corretta o se dovrei fare qualcosa di diverso?

Risposte:


252

Bene, ci sono alcuni modi per farlo a seconda del comportamento previsto, ma questo link dovrebbe darti tutte le migliori soluzioni e non a caso proviene da Dianne Hackborn

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

Essenzialmente hai le seguenti opzioni

  • Utilizzare un nome per lo stato iniziale dello stack posteriore e utilizzare FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Utilizzare FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() per recuperare l'ID della prima voce nello stack posteriore e FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) dovrebbe far scoppiare l'intero back stack ... Penso che la documentazione sia sbagliata. (In realtà immagino che non copra il caso in cui si passa POP_BACK_STACK_INCLUSIVE),

Cosa significa questo? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). GetId ()
dannyroa

4
2o ha lavorato per me. Cosa significa cancellare l'intero stack: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL

@JorgeGarcia è possibile dopo il popbackstack abbiamo appena finito il nostro frammento senza riavviare quello precedente.
duggu,

Si noti che esiste anche la versione popBackStackImmediate () poiché popBackStack () è asincrono, il che significa che la pulizia non si verifica nel momento esatto in cui si chiama il metodo.
Genc,

6
Sostiene che il gruppo è stato bandito come spam e non riesco ad accedere al link :( qualcuno ha la risorsa altrove?
EpicPandaForce

61

L'altra soluzione pulita se non vuoi far apparire tutte le voci dello stack ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

Questo pulirà prima lo stack e quindi caricherà un nuovo frammento, quindi in un dato punto avrai solo un singolo frammento nello stack


1
Questo è molto male: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);prima di un replace (), perché sta caricando la chiamata Frammento onCreateView(), onActivityCreated()ecc Ripristino e destroing un frammento è immediatamente male. Ad esempio, il frammento può registrare un ricevitore. Questo influisce sulle prestazioni.
VasileM,

@VasileM, potresti descriverlo in dettaglio? In quali casi è male? È a causa del comportamento asincrono di FragmentTransaction? Esistono solo cattive prestazioni dello stack di frammenti sbagliato?
CoolMind il

27

Grazie alla risposta di Joachim , uso finalmente il codice per cancellare tutte le voci di back stack.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
Perché usare un loop qui? Per me FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) ha cancellato tutte le voci dello stack posteriore ...
Marek,

3
@Marek, perché a volte non tutti i frammenti devono essere rimossi, un loop è adatto a questo.
CoolMind

1
@CoolMind, non ha ancora senso per me. popBackStack(backStackId, INCLUSIVE)farà apparire tutti i frammenti (stati) di nuovo in backStackId, quindi una volta che fai il pop più basso iche stai per pop, tutti quelli più alti dovrebbero essere spuntati allo stesso tempo. Allora, qual è il punto di un ciclo?
LarsH,

@LarsH, hai ragione. Vedi stackoverflow.com/a/59158254/2914140 . Per inserire altri frammenti nel tag richiesto, dovremmo prima aggiungere il frammento con addToBackStack ( tag ).
CoolMind il

7

Ho studiato molto per la pulizia del Backstack e finalmente vedo Transaction BackStack e la sua gestione . Ecco la soluzione che ha funzionato meglio per me.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

Il metodo sopra riportato esegue il ciclo su tutte le transazioni nel backstack e le rimuove immediatamente una alla volta.

Nota: il codice sopra a volte non funziona e ho riscontrato ANR a causa di questo codice, quindi per favore non provarlo.

Il metodo di aggiornamento di seguito rimuove dal backstack tutti i tipi di "nome" liberi.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • nome Se non nullo, questo è il nome di uno stato precedente precedente da cercare; se trovato, verranno visualizzati tutti gli stati fino a quello stato. Il
  • Il flag POP_BACK_STACK_INCLUSIVE può essere utilizzato per controllare se lo stato denominato stesso viene visualizzato. Se null, viene visualizzato solo lo stato superiore.

Non vedo perché li rimuoveresti uno alla volta. C'è un motivo per cui hai scelto questa soluzione invece delle altre soluzioni? C'è un motivo per rimuoverli uno alla volta anziché tutti contemporaneamente?
miva2,

non esiste un metodo per rimuovere lo zaino in una sola volta, vedi developer.android.com/reference/android/app/…
Lokesh,

3

Sto usando un codice simile a quelli che usano il ciclo while ma chiamo il conteggio delle voci in ogni ciclo ... quindi suppongo che sia un po 'più lento

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

Come scritto in Come estrarre il frammento dallo backstack e da LarsH qui, possiamo pop diversi frammenti dall'alto verso il basso al tag specifico ( insieme al frammento con tag ) usando questo metodo:

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

Sostituisci "frag" con il tag del tuo frammento. Ricorda che per prima cosa dovremmo aggiungere il frammento al backstack con:

fragmentTransaction.addToBackStack("frag")

Se aggiungiamo frammenti con addToBackStack(null), non pop i frammenti in quel modo.


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
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.