Wyczyść stos za pomocą fragmentów

244

Przeniesiłem moją aplikację na Androida do plastra miodu i zrobiłem duży refaktor, aby użyć fragmentów. W mojej poprzedniej wersji, kiedy nacisnąłem przycisk Home, robiłem a ACTIVITY_CLEAR_TOP, aby zresetować tylny stos.

Teraz moja aplikacja to tylko jedno działanie z wieloma fragmentami, więc po naciśnięciu przycisku Początek po prostu zastępuję jeden z zawartych w nim fragmentów. Jak mogę usunąć moje plecy stos bez konieczności korzystania startActivityz ACTIVITY_CLEAR_TOPflag?

biquillo
źródło
Unikaj używania stosów pleców! tak naprawdę nie pomaga w ogólnej wydajności! użyj zwykłego replace () lub nawet lepiej usuń / dodaj za każdym razem, gdy chcesz nawigować! Sprawdź mój post na stackoverflow.com/questions/5802141/…
stack_ved,

Odpowiedzi:

430

Opublikowałem tutaj coś podobnego

Z odpowiedzi Joachima, Dianne Hackborn:

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

Skończyło się na tym, że użyłem:

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

Ale równie dobrze mógł użyć czegoś takiego:

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

Który wyskoczy wszystkie stany do podanego. Następnie możesz po prostu zastąpić fragment tym, co chcesz

PJL
źródło
8
Odpowiada to jednokrotnemu naciśnięciu przycisku Wstecz, więc zmienia fragment, który jest obecnie widoczny. (Przynajmniej kiedy spróbowałem)
Peter Ajtai
7
Mam ten sam problem co Peter. Chciałbym usunąć wszystkie fragmenty, zamiast je cyklicznie przewijać, co ma wiele implikacji. Na przykład trafisz na zdarzenia cyklu życia, których nie potrzebujesz, usuwając kolejno każdy fragment ze stosu.
Brian Griffey,
233
Aby przejść na górę, użyj: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit,
53
Za to, co jest warte, używając fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); działało dla mnie jeszcze lepiej, ponieważ uniemożliwiało wykonanie animacji fragmentu
roarster,
17
To NIE DZIAŁA poprawnie - spowoduje wywołanie onStart każdego fragmentu pomiędzy
James
165

Aby udzielić odpowiedzi na komentarz @ Warpzit i ułatwić innym znalezienie.

Posługiwać się:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Morten Holmgaard
źródło
14
Wydaje mi się, że usuwanie wszystkich fragmentów z backstacka w ten sposób zostało przerwane w najnowszej bibliotece v7-appCompat podczas używania AppCompatActivity. Po zaktualizowaniu mojej aplikacji do najnowszej biblioteki v7-appCompat (21.0.0) i rozszerzeniu nowej AppCompatActivity wyskakujące fragmenty w powyższy sposób pozostawiają niektóre fragmenty w rekordzie backstack FragmentManager. Odradzam korzystanie z tego.
dell116
Może być użyty popBackStackImmediate.
Kannan_SJD
38

Z całym szacunkiem dla wszystkich zaangażowanych stron; Jestem bardzo zaskoczony, widząc, jak wielu z was może wyczyścić cały stos za pomocą prostego

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zgodnie z dokumentacją Androida (w odniesieniu do nameargumentu - „zero” w zastrzeżonych propozycjach roboczych).

Jeśli jest pusty, pojawia się tylko stan najwyższy

Teraz zdaję sobie sprawę, że brakuje mi wiedzy o twoich konkretnych implementacjach (np. Ile wpisów masz na tylnym stosie w danym momencie), ale postawiłbym wszystkie moje pieniądze na przyjętą odpowiedź, oczekując dobrze zdefiniowanej odpowiedzi zachowanie w szerszym zakresie urządzeń i dostawców:

(dla porównania, coś z tym)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}
dbm
źródło
4
dla mnie nie było tak, ponieważ każdy pop zabiera cię wewnętrznie do onCreateView każdego fragmentu. Gdzie otrzymam NPE na jakiś zasób. Ale za pomocą fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); po prostu zabił cały plecak.
sud007
1
Jakieś spostrzeżenia na temat pomijania połączeń onCreateView podczas otwierania za pomocą pętli?
Ayush Goyal,
Wyczyszczenie najwyższego fragmentu (null) usunie wszystkie fragmenty, które występują po nim na tylnym stosie.
2b77bee6-5445-4c77-b1eb-4df3e5
18

Działa dla mnie w prosty sposób bez użycia pętli:

 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
źródło
17

Zaakceptowana odpowiedź nie była dla mnie wystarczająca. Musiałem użyć:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}
belphegor
źródło
2
Zostało to wskazane w innej odpowiedzi, ale tylko dla pewności, że zostało to odnotowane: jeśli wrzucisz cały stos w taką pętlę, uruchomisz metody cyklu życia dla każdego fragmentu pomiędzy początkiem i końcem stosu . Istnieje duża szansa, że ​​wdrożenie to miałoby niezamierzone konsekwencje, w większości przypadków użycia. Warto również zauważyć, że popBackStackImmediate()transakcja jest przeprowadzana synchronicznie, co na ogół jest odradzane.
Damien Diehl
16

Wyczyść backstack bez pętli

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

Gdzie nazwa jest parametrem addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)
georgehardcore
źródło
nawet jeśli zastąpisz .fragment stos będzie żywy, ale niewidoczny
Asthme
8

Chciałem tylko dodać:

Wyskakujące ze stosu za pomocą następujących

fragmentManager.popBackStack ()

chodzi tylko o usunięcie fragmentów z transakcji, w żaden sposób nie usunie tego fragmentu z ekranu. Idealnie więc może nie być dla ciebie widoczny, ale mogą znajdować się dwa lub trzy fragmenty ułożone jeden na drugim, a po naciśnięciu klawisza wstecz interfejs użytkownika może wyglądać na zagracony, ułożony w stos.

Biorąc prosty przykład: -

Załóżmy, że masz fragment A, który ładuje Fragmnet B za pomocą fragmentmanager.replace (), a następnie dodajemyToBackStack, aby zapisać tę transakcję. Więc przepływ jest:

KROK 1 -> Fragment A-> Fragment B (przenieśliśmy się do Fragmentu B, ale Fragment A jest w tle, niewidoczny).

Teraz wykonujesz trochę pracy we fragmencie B i naciskasz przycisk Zapisz - który po zapisaniu powinien wrócić do fragmentu A.

KROK 2-> Po zapisaniu Fragmentu B wracamy do Fragmentu A.

KROK 3 -> Tak częstym błędem byłoby ... we fragmencie B, zrobimy fragment Manager.replace () fragmentB z fragmentem A.

Ale to, co się faktycznie dzieje, ponownie ładujemy Fragment A, zastępując Fragment B. Więc teraz są dwa FragmentA (jeden ze STEP-1 i jeden z tego STEP-3).

Dwa wystąpienia Fragmentów A są ułożone jeden na drugim, co może nie być widoczne, ale już tam jest.

Więc nawet jeśli wyczyścimy backstack powyższymi metodami, transakcja zostanie wyczyszczona, ale nie rzeczywiste fragmenty. Idealnie więc w takim szczególnym przypadku po naciśnięciu przycisku Zapisz wystarczy wrócić do fragmentu A, wykonując po prostu fm.popBackStack () lub fm.popBackImmediate () .

Więc popraw Step3-> fm.popBackStack () wróć do fragmentu A, który jest już w pamięci.

Nicki
źródło
3

Czytając dokumentację i badając identyfikator fragmentu, wydaje się, że jest to po prostu indeks stosu, więc działa to:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero ( 0) jest dolną częścią stosu, więc pojawienie się na nim łącznie usuwa stos.

CAVEAT: Chociaż powyższe działa w moim programie, waham się trochę, ponieważ dokumentacja FragmentManager nigdy tak naprawdę nie stwierdza, że ​​id jest indeksem stosu. Ma to sens, a wszystkie moje dzienniki debugowania odsłaniają, że tak jest, ale być może w szczególnych okolicznościach tak się nie stanie? Czy ktoś może to potwierdzić w ten czy inny sposób? Jeśli tak, to powyższe jest najlepszym rozwiązaniem. Jeśli nie, jest to alternatywa:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
przeł
źródło
1
Co powiesz na użycie fragmentManager..getBackStackEntryAt(0).getId()zamiast 0? Powinno to działać, nawet jeśli identyfikatory pozycji backstack są w pewnym momencie inne niż indeks stosu.
ChristophK,
3

Po prostu użyj tej metody i przekaż znacznik Context & Fragment w górę, aby usunąć fragmenty wsteczne.

Stosowanie

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
źródło
2

Cześć ~ Znalazłem rozwiązanie, które jest znacznie lepsze, od: 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
źródło
2
Rozwiń swoją odpowiedź, dlaczego to rozwiązanie jest lepsze.
Simon.SA
Korzysta z mechanizmu dostarczanego przez sdk i nie spowoduje jakiegoś problemu npe.
Chenxi,
1

Mam to działające w ten sposób:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}
saulobrito
źródło
1

Działa dla mnie, spróbuj tego:

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

Wywołanie tej metody byłoby bardzo miłe.

  1. Pętla nie jest wymagana.
  2. Jeśli używasz animacji we fragmentach, nie wyświetli ona zbyt wielu animacji. Ale użycie pętli będzie.
Wajid Ali
źródło
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;
}
użytkownik3509903
źródło
Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie byłoby znacznie poprawić swoją długoterminową wartość pokazując dlaczego jest to dobre rozwiązanie problemu i byłoby bardziej użyteczne dla czytelników przyszłości z innymi, podobnymi pytaniami. Proszę edytować swoją odpowiedź dodać kilka wyjaśnień, w tym założeń już wykonanych.
Abdelilah El Aissaoui