Löschen Sie den Rückstapel mit Fragmenten

244

Ich habe meine Android-App auf Honeycomb portiert und einen großen Refactor durchgeführt, um Fragmente zu verwenden. In meiner vorherigen Version habe ich beim Drücken der Home-Taste a ausgeführt, ACTIVITY_CLEAR_TOPum den Backstack zurückzusetzen.

Jetzt ist meine App nur eine einzelne Aktivität mit mehreren Fragmenten. Wenn ich also die Home-Taste drücke, ersetze ich einfach eines der darin enthaltenen Fragmente. Wie kann ich meinen Backstack löschen, ohne ihn startActivitymit der ACTIVITY_CLEAR_TOPFlagge verwenden zu müssen?

Biquillo
quelle
Vermeiden Sie Rückstapel! es hilft nicht wirklich bei der Gesamteffizienz! Verwenden Sie Plain Replace () oder entfernen / fügen Sie jedes Mal, wenn Sie navigieren möchten, noch besser! Überprüfen Sie meinen Beitrag auf stackoverflow.com/questions/5802141/…
stack_ved

Antworten:

430

Ich habe hier etwas Ähnliches gepostet

Aus Joachims Antwort, aus Dianne Hackborn:

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

Am Ende habe ich nur verwendet:

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

Hätte aber auch so etwas gebrauchen können:

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

Dadurch werden alle Zustände bis zu dem genannten angezeigt. Sie können das Fragment dann einfach durch das ersetzen, was Sie möchten

PJL
quelle
8
Nun, es entspricht einem ein- oder mehrmaligen Drücken der Zurück-Taste, sodass das aktuell sichtbare Fragment geändert wird. (Zumindest wenn ich es versucht habe)
Peter Ajtai
7
Ich habe das gleiche Problem wie Peter. Ich möchte alle Fragmente entfernen, anstatt sie durchlaufen zu lassen, was viele Auswirkungen hat. Beispielsweise treffen Sie Lebenszyklusereignisse, die Sie nicht benötigen, indem Sie jedes Fragment nacheinander vom Stapel entfernen.
Brian Griffey
233
Um nach oben zu gelangen, verwenden Sie einfach: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit
53
Für das, was es wert ist, verwenden Sie fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); funktionierte noch besser für mich, da es die Ausführung der Fragmentanimationen verhinderte
Roarster
17
Dies funktioniert NICHT richtig - es wird ein Aufruf von onStart für jedes Fragment dazwischen ausgelöst
James
165

Um eine Antwort auf den Kommentar von @ Warpzit zu geben und anderen das Auffinden zu erleichtern.

Verwenden:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Morten Holmgaard
quelle
14
Ich glaube, dass das Löschen aller Fragmente aus dem Backstack auf diese Weise in der neuesten v7-appCompat-Bibliothek bei Verwendung von AppCompatActivity beschädigt wurde. Nachdem ich meine App auf die neueste v7-appCompat-Bibliothek (21.0.0) aktualisiert und die neue AppCompatActivity erweitert habe, bleiben beim Fragmenten auf die oben beschriebene Weise einige Fragmente im Backstack-Datensatz des FragmentManager. Ich würde davon abraten.
Dell116
Kann popBackStackImmediate verwenden.
Kannan_SJD
38

Bei allem Respekt gegenüber allen Beteiligten; Ich bin sehr überrascht zu sehen, wie viele von Ihnen den gesamten Fragment-Backstack mit einem einfachen löschen können

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Laut Android-Dokumentation (bezüglich des nameArguments - die "Null" in den beanspruchten Arbeitsvorschlägen).

Wenn null, wird nur der oberste Status angezeigt

Jetzt ist mir klar, dass mir Kenntnisse über Ihre speziellen Implementierungen fehlen (z. B. wie viele Einträge Sie zu einem bestimmten Zeitpunkt im Backstack haben), aber ich würde mein ganzes Geld auf die akzeptierte Antwort setzen, wenn ich eine genau definierte Antwort erwarte Verhalten über eine größere Anzahl von Geräten und Anbietern:

(als Referenz etwas dazu)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}
dbm
quelle
4
Für mich war es nicht so, dass jeder Pop Sie intern zur onCreateView jedes Fragments führt. Wo ich eine NPE für eine Ressource erhalten würde. Aber mit fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); einfach den ganzen Backstack getötet.
Sud007
1
Gibt es Einblicke, wie Sie onCreateView-Aufrufe überspringen können, wenn Sie mit loop eine Popup-Funktion ausführen?
Ayush Goyal
Durch Löschen des obersten Fragments (null) werden alle nachfolgenden Fragmente im hinteren Stapel gelöscht.
2b77bee6-5445-4c77-b1eb-4df3e5
18

Funktioniert für mich und auf einfache Weise ohne Schleife:

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

Akzeptierte Antwort war mir nicht genug. Ich musste verwenden:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}
Belphegor
quelle
2
Dies wurde in einer anderen Antwort hervorgehoben, aber nur um sicherzugehen, dass Folgendes vermerkt ist: Wenn Sie den gesamten Stapel in einer Schleife wie dieser platzieren, werden Sie die Lebenszyklusmethoden für jedes Fragment zwischen dem Anfang und dem Ende des Stapels auslösen . Es besteht eine gute Chance, dass diese Implementierung in den meisten Anwendungsfällen unbeabsichtigte Konsequenzen hat. Es ist auch erwähnenswert, dass popBackStackImmediate()die Transaktion synchron ausgeführt wird, was im Allgemeinen nicht ratsam ist.
Damien Diehl
16

Clear Backstack ohne Schleifen

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

Wobei Name der Parameter addToBackStack () ist

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)
George Hardcore
quelle
Auch wenn Sie .fragment Stack ersetzen, wird lebendig, aber nicht sichtbar
Asthme
8

Ich wollte nur hinzufügen: -

Herausspringen aus dem Backstack mit folgenden Schritten

fragmentManager.popBackStack ()

Es geht nur darum, die Fragmente aus der Transaktion zu entfernen. Auf keinen Fall wird das Fragment vom Bildschirm entfernt. Im Idealfall ist es für Sie möglicherweise nicht sichtbar, aber möglicherweise sind zwei oder drei Fragmente übereinander gestapelt, und beim Drücken der Zurück-Taste sieht die Benutzeroberfläche möglicherweise überladen und gestapelt aus.

Nehmen wir nur ein einfaches Beispiel: -

Angenommen, Sie haben ein FragmentA, das Fragmnet B mit fragmentmanager.replace () lädt, und dann fügen wir AddBoStack hinzu, um diese Transaktion zu speichern. Der Fluss ist also:

SCHRITT 1 -> FragmentA-> FragmentB (wir sind zu FragmentB übergegangen, aber Fragment A befindet sich im Hintergrund und ist nicht sichtbar).

Jetzt erledigen Sie einige Arbeiten in FragmentB und klicken auf die Schaltfläche Speichern. Nach dem Speichern sollte wieder zu FragmentA zurückkehren.

SCHRITT 2-> Beim Speichern von FragmentB kehren wir zu FragmentA zurück.

SCHRITT 3 -> Ein häufiger Fehler wäre also ... in Fragment B werden wir fragment Manager.replace () fragmentB mit fragmentA ausführen.

Aber was tatsächlich passiert, wir laden Fragment A erneut und ersetzen Fragment B. Jetzt gibt es also zwei FragmentA (eines aus STEP-1 und eines aus diesem STEP-3).

Zwei Instanzen von FragmentenA sind übereinander gestapelt, was möglicherweise nicht sichtbar ist, aber vorhanden ist.

Selbst wenn wir den Backstack mit den oben genannten Methoden löschen, wird die Transaktion gelöscht, nicht jedoch die tatsächlichen Fragmente. Idealerweise müssen Sie in einem solchen speziellen Fall beim Drücken der Schaltfläche Speichern einfach zu fragmentA zurückkehren, indem Sie einfach fm.popBackStack () oder fm.popBackImmediate () ausführen .

Also richtig Step3-> fm.popBackStack () gehe zurück zu fragmentA, das sich bereits im Speicher befindet.

Nicks
quelle
3

Wenn Sie die Dokumentation lesen und die Fragment-ID untersuchen, scheint es sich lediglich um den Stapelindex zu handeln. Dies funktioniert also:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Null ( 0) ist die Unterseite des Stapels. Wenn Sie also einschließlich aufspringen, wird der Stapel gelöscht.

CAVEAT: Obwohl das oben Genannte in meinem Programm funktioniert, zögere ich ein wenig, da in der FragmentManager-Dokumentation nie angegeben wird, dass die ID der Stapelindex ist. Es macht Sinn, dass es so wäre, und alle meine Debug-Protokolle zeigen, dass es so ist, aber vielleicht würde es unter bestimmten Umständen nicht so sein? Kann jemand dies auf die eine oder andere Weise bestätigen? Wenn dies der Fall ist, ist das Obige die beste Lösung. Wenn nicht, ist dies die Alternative:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
trans
quelle
1
Wie wäre es mit fragmentManager..getBackStackEntryAt(0).getId()anstelle von 0? Dies sollte auch dann funktionieren, wenn sich die Backstack-Eintrags-IDs irgendwann vom Stapelindex unterscheiden.
ChristophK
3

Verwenden Sie einfach diese Methode und übergeben Sie das Context & Fragment-Tag, an das wir die Backstake-Fragmente entfernen müssen.

Verwendung

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();
    }
}
Arhat Baid
quelle
2

Hallo ~ Ich habe eine Lösung gefunden, die viel besser ist: 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);
    }
}
Chenxi
quelle
2
Bitte erweitern Sie Ihre Antwort mit dem Grund, warum diese Lösung besser ist.
Simon.SA
Es verwendet den Mechanismus, den das SDK selbst bereitstellt, und verursacht keine Npe-Probleme.
Chenxi
1

Ich habe das so gemacht:

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

Es funktioniert für mich, versuchen Sie dieses:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }
Alok Singh
quelle
0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Der Aufruf dieser Methode wäre sehr ordentlich.

  1. Keine Schleife erforderlich.
  2. Wenn Sie Animationen in Fragmenten verwenden, werden nicht zu viele Animationen angezeigt. Aber mit Schleife wird.
Wajid Ali
quelle
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;
}
user3509903
quelle
Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte und sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Abdelilah El Aissaoui