Cancella lo stack posteriore usando i frammenti


244

Ho portato la mia app Android a nido d'ape e ho fatto un grande refactoring per usare i frammenti. Nella mia versione precedente, quando premevo il pulsante Home, ero solito fare una ACTIVITY_CLEAR_TOPper ripristinare lo stack posteriore.

Ora la mia app è solo una singola attività con più frammenti, quindi quando premo il pulsante Home sostituisco solo uno dei frammenti al suo interno. Come posso cancellare il mio back stack senza dover usare startActivitycon la ACTIVITY_CLEAR_TOPbandiera?


Evitare l'uso di pile posteriori! non aiuta davvero con l'efficienza complessiva! usa plain sostituisci () o ancora meglio rimuovi / aggiungi ogni volta che vuoi navigare! Controllare il mio post su stackoverflow.com/questions/5802141/...
stack_ved

Risposte:


430

Ho pubblicato qualcosa di simile qui

Dalla risposta di Joachim, da Dianne Hackborn:

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

Ho finito per usare solo:

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

Ma avrebbe potuto usare allo stesso modo qualcosa di simile:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

Che farà apparire tutti gli stati fino a quello indicato. Puoi quindi sostituire il frammento con quello che desideri


8
Bene, equivale a premere il pulsante Indietro una o più volte, quindi cambia il frammento che è attualmente visibile. (Almeno quando l'ho provato)
Peter Ajtai,

7
Sto riscontrando lo stesso problema di Peter. Vorrei eliminare tutti i frammenti piuttosto che farli scorrere tra loro, il che ha molte implicazioni. Ad esempio, colpirai gli eventi del ciclo di vita che non ti servono eliminando sequenzialmente ogni frammento dallo stack.
Brian Griffey,

233
Per andare in cima usa semplicemente: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit,

53
Per quello che vale, usando fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); ha funzionato ancora meglio per me poiché ha impedito l'esecuzione delle animazioni di frammenti
roarster

17
Questo NON funziona correttamente - attiverà una chiamata a Start di ogni frammento in mezzo
James

165

Per rispondere al commento di @ Warpzit e facilitare la ricerca di altri.

Uso:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Credo che il fatto di aver rimosso tutti i frammenti dallo zaino in questo modo sia stato rotto nell'ultima libreria v7-appCompat quando si utilizza AppCompatActivity. Dopo aver aggiornato la mia app all'ultima libreria v7-appCompat (21.0.0) e aver ampliato la nuova AppCompatActivity, il pop-up dei frammenti nel modo sopra sta lasciando alcuni frammenti nel record di backstack di FragmentManager. Sconsiglio di usare questo.
dell116,

Può essere utilizzato popBackStackImmediate.
Kannan_SJD,

38

Con tutto il rispetto per tutte le parti interessate; Sono molto sorpreso di vedere quanti di voi potrebbero cancellare l'intero stack di frammenti con un semplice

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Secondo la documentazione Android (per quanto riguarda l' nameargomento - il "null" nelle proposte di lavoro dichiarate).

Se null, viene visualizzato solo lo stato superiore

Ora, mi rendo conto che mi manca la conoscenza delle tue implementazioni particolari (come quante voci hai nello stack posteriore in un determinato momento), ma scommetterei tutti i miei soldi sulla risposta accettata quando mi aspetto una definizione ben definita comportamento su una gamma più ampia di dispositivi e fornitori:

(per riferimento, qualcosa insieme a questo)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

4
per me non è stato dal momento che ogni pop ti porta internamente alla onCreateView di ogni frammento. Dove avrei ricevuto un NPE su alcune risorse. Ma usando fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); semplicemente ucciso tutto lo zaino.
sud007,

1
Qualche idea su come saltare le chiamate onCreateView quando si fa il popping usando il loop?
Ayush Goyal,

L'eliminazione del frammento più in alto (null) eliminerà tutti i frammenti che lo seguono nello stack posteriore.
2b77bee6-5445-4c77-b1eb-4df3e5

18

Funziona per me e in modo semplice senza usare loop:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

La risposta accettata non era abbastanza per me. Ho dovuto usare:

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

2
Questo è stato sottolineato in una risposta diversa, ma solo per assicurarsi che sia notato: se fai scoppiare l'intero stack in un ciclo come questo, attiverai i metodi del ciclo di vita per ogni frammento tra l'inizio e la fine dello stack . Vi sono buone probabilità che questa implementazione abbia conseguenze indesiderate, nella maggior parte dei casi d'uso. Vale anche la pena sottolineare che popBackStackImmediate()esegue la transazione in modo sincrono, che è generalmente sconsigliato.
Damien Diehl,

16

Zaino trasparente senza anelli

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Dove name è il parametro addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

anche se sostituisci lo stack .fragment sarà vivo ma non visibile
Asma

8

Volevo solo aggiungere: -

Esci dal backstack usando quanto segue

fragmentManager.popBackStack ()

si tratta solo di rimuovere i frammenti dalla transazione, in nessun modo rimuoverà il frammento dallo schermo. Quindi, idealmente, potrebbe non essere visibile a te, ma potrebbero esserci due o tre frammenti sovrapposti l'uno sull'altro, e premendo il tasto Indietro l'interfaccia utente può apparire ingombra, impilata.

Basta fare un semplice esempio: -

Supponiamo di avere un frammento A che carica Fragmnet B usando fragmentmanager.replace () e quindi aggiungiamo ToBackStack per salvare questa transazione. Quindi il flusso è: -

PASSAGGIO 1 -> Frammento A-> Frammento B (siamo passati al frammento B, ma il frammento A è in background, non visibile).

Ora fai qualche lavoro nel frammento B e premi il pulsante Salva, che dopo il salvataggio dovrebbe tornare al frammento A.

PASSAGGIO 2-> Al salvataggio di FragmentB, torniamo a FragmentA.

PASSAGGIO 3 -> Quindi l'errore comune sarebbe ... nel frammento B, faremo frammento Manager.replace () fragmentB con frammentoA.

Ma quello che sta realmente accadendo, stiamo caricando di nuovo il frammento A, sostituendo il frammento B. Quindi ora ci sono due frammenti A (uno da STEP-1 e uno da questo STEP-3).

Due istanze di frammenti A sono sovrapposte, che potrebbero non essere visibili, ma è lì.

Quindi, anche se cancelliamo il backstack con i metodi sopra, la transazione viene cancellata ma non i frammenti effettivi. Quindi idealmente in un caso così particolare, premendo il pulsante Salva è sufficiente tornare al frammento A semplicemente facendo fm.popBackStack () o fm.popBackImmediate () .

Quindi, corretto Step3-> fm.popBackStack () torna al frammento A, che è già in memoria.


3

Leggendo la documentazione e studiando quale sia l'id del frammento, sembra semplicemente essere l'indice dello stack, quindi funziona:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero ( 0) è il fondo della pila, quindi saltargli sopra inclusivo cancella la pila.

CAVEAT: Sebbene quanto sopra funzioni nel mio programma, esito un po 'perché la documentazione di FragmentManager non afferma mai che l'id sia l'indice dello stack. Ha senso che lo sia, e tutti i miei registri di debug lo rivelano, ma forse in qualche circostanza speciale non lo sarebbe? Qualcuno può confermare in un modo o nell'altro? Se lo è, allora quanto sopra è la soluzione migliore. In caso contrario, questa è l'alternativa:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
Che ne dici di usare fragmentManager..getBackStackEntryAt(0).getId()invece di 0? Questo dovrebbe funzionare anche se gli ID della voce di backstack sono in qualche punto diversi dall'indice dello stack.
ChristophK,

3

Basta usare questo metodo e passare il tag Context & Fragment a cui dobbiamo rimuovere i frammenti di backstake.

uso

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

2

Ciao ~ Ho trovato una soluzione molto migliore, da: https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

2
Espandi la tua risposta sul perché questa soluzione è migliore.
Simon.SA,

Utilizza il meccanismo fornito da sdk e non causa alcun problema di npe.
Chenxi,

1

Ho funzionato in questo modo:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

Funziona per me, prova questo:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

La chiamata a questo metodo sarebbe molto accurata.

  1. Nessun loop richiesto.
  2. Se si utilizza l'animazione in frammenti, non mostrerà troppe animazioni. Ma usando loop lo farà.

0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

Grazie per questo frammento di codice, che potrebbe fornire un aiuto limitato e immediato. Una spiegazione adeguata migliorerebbe notevolmente il suo valore a lungo termine mostrando perché questa è una buona soluzione al problema e la renderebbe più utile ai futuri lettori con altre domande simili. Si prega di modificare la risposta di aggiungere qualche spiegazione, tra le ipotesi che hai fatto.
Abdelilah El Aissaoui,
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.