Czy to właściwy sposób na uporządkowanie tylnego stosu Fragmentów po pozostawieniu głęboko zagnieżdżonego stosu?

130

Używam biblioteki Android Compatibility do implementowania fragmentów i rozszerzyłem przykładowy układ, tak aby fragment zawierał przycisk, który odpala inny fragment.

W okienku wyboru po lewej stronie mam 5 elementów do wyboru - A B C D E.

Każdy ładuje fragment (przez FragmentTransaction:replace) w okienku szczegółów -a b c d e

Teraz rozszerzyłem fragment, eaby zawierał przycisk, który ładuje kolejny fragment e1również w okienku szczegółów. Zrobiłem to na emetodzie onClick fragmentu w następujący sposób:

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

Jeśli dokonam następujących wyborów:

E - e - e1 - D - E

Następnie fragment eznajduje się w okienku szczegółów. To jest w porządku i czego chcę. Jeśli jednak backw tym momencie wcisnę przycisk, to nic nie robi. Muszę kliknąć dwukrotnie, ponieważ e1wciąż jest na stosie. Ponadto po kliknięciu w onCreateView pojawił się wyjątek wskaźnika zerowego:

Aby `` rozwiązać '' ten problem, dodałem następujące po A B C D Ewybraniu:

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

Zastanawiam się tylko, czy to jest właściwe rozwiązanie, czy też powinienem robić coś innego?

PJL
źródło

Odpowiedzi:

252

Cóż, jest kilka sposobów, aby to zrobić, w zależności od zamierzonego zachowania, ale ten link powinien dać ci najlepsze rozwiązania i nie jest zaskoczeniem, że pochodzi od Dianne Hackborn

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

Zasadniczo masz następujące opcje

  • Użyj nazwy dla początkowego stanu stosu wstecznego i użyj FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Użyj FragmentManager.getBackStackEntryCount()/, getBackStackEntryAt().getId() aby pobrać identyfikator pierwszego wpisu na tylnym stosie i FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) ma usunąć cały tylny stos ... Myślę, że dokumentacja jest po prostu błędna. (Właściwie myślę, że to po prostu nie obejmuje przypadku, gdy przechodzisz POP_BACK_STACK_INCLUSIVE),
Joachim
źródło
Co to znaczy? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). GetId ()
dannyroa
4
2nd pracował dla mnie. Co to oznacza wyczyszczenie całego stosu: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL
@JorgeGarcia jest możliwe, że po popbackstacku skończymy nasz fragment bez restartowania starszego.
duggu
Należy pamiętać, że istnieje również wersja popBackStackImmediate (), ponieważ popBackStack () jest asynchroniczna, co oznacza, że ​​czyszczenie nie następuje dokładnie w momencie wywołania metody.
Genc
6
Twierdzi, że grupa została zbanowana jako spam i nie mogę uzyskać dostępu do linku :( czy ktoś ma zasoby gdzie indziej?
EpicPandaForce
61

Innym czystym rozwiązaniem, jeśli nie chcesz usuwać wszystkich wpisów stosu ...

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

Spowoduje to najpierw wyczyszczenie stosu, a następnie załadowanie nowego fragmentu, więc w dowolnym momencie będziesz mieć tylko jeden fragment w stosie

Pawan Maheshwari
źródło
1
To jest bardzo złe: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);przed replace (), ponieważ są załadowaniu powołanie Fragment onCreateView(), onActivityCreated()itp Przywracanie i destroing fragment od razu jest zły. Fragment może na przykład zarejestrować odbiornik. Wpływa to na wydajność.
VasileM
@VasileM, czy mógłbyś szczegółowo opisać? W jakich przypadkach jest źle? Czy to z powodu asynhronicznego zachowania FragmentTransaction? Czy jest tylko zła wydajność złego stosu fragmentów?
CoolMind
27

Dzięki odpowiedzi Joachima używam kodu, aby w końcu wyczyścić wszystkie wpisy na stosie.

// 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 */
Jay Parker
źródło
18
Po co tu używać pętli? Dla mnie FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) wyczyścił wszystkie wpisy z tyłu stosu ...
Marek
3
@Marek, bo czasami nie wszystkie fragmenty należy usunąć, do tego nadaje się pętla.
CoolMind
1
@CoolMind, to nadal nie ma dla mnie sensu. popBackStack(backStackId, INCLUSIVE)wrzuci wszystkie fragmenty (stany) z powrotem do backStackId, więc kiedy zdejmiesz najniższy i, który zamierzasz, wszystkie wyższe powinny zostać usunięte w tym samym czasie. Więc jaki jest sens pętli?
LarsH
@LarsH, masz rację. Zobacz stackoverflow.com/a/59158254/2914140 . Aby wstawić inne fragmenty do wymaganego tagu, należy najpierw dodać fragment za pomocą addToBackStack ( tag ).
CoolMind
8

Dużo badałem, aby wyczyścić Backstack i wreszcie zobaczyłem Transaction BackStack i zarządzanie nim . Oto rozwiązanie, które najlepiej mi się sprawdziło.

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

Powyższa metoda zapętla wszystkie transakcje w backstacku i usuwa je natychmiast po jednej na raz.

Uwaga: powyższy kod czasami nie działa i napotykam błąd ANR z powodu tego kodu, więc nie próbuj tego.

Zaktualizuj poniższą metodę, aby usunąć wszystkie zwolnienia tej „nazwy” z backstacka.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • nazwa Jeśli nie jest pusta, jest to nazwa poprzedniego stanu wstecznego do wyszukania; jeśli zostanie znaleziony, wszystkie stany do tego stanu zostaną usunięte. Plik
  • Flaga POP_BACK_STACK_INCLUSIVE może służyć do kontrolowania, czy sam nazwany stan jest otwierany. Jeśli null, tylko najwyższy stan jest usuwany.
Lokesh
źródło
Nie rozumiem, dlaczego miałbyś je usuwać pojedynczo. Czy jest jakiś powód, dla którego wybrałeś to rozwiązanie zamiast innych? Czy istnieje powód, aby usuwać je pojedynczo zamiast wszystkich naraz?
miva2
nie ma metody na jednorazowe usunięcie backstacka patrz developer.android.com/reference/android/app/…
Lokesh
3

Używam podobnego kodu jak te, które używają pętli while, ale wywołuję liczbę wejść w każdej pętli ... więc przypuszczam, że jest nieco wolniejszy

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }
Jorge Lozano
źródło
0

Jak napisano w Jak zdjąć fragment z backstacka i LarsH tutaj, możemy przeskoczyć kilka fragmentów od góry do dołu do konkretnego tagu ( razem z tagowanym fragmentem ) przy użyciu tej metody:

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

Zastąp „frag” tagiem swojego fragmentu. Pamiętaj, że najpierw powinniśmy dodać fragment do backstacka za pomocą:

fragmentTransaction.addToBackStack("frag")

Jeśli dodamy fragmenty za pomocą addToBackStack(null), nie będziemy usuwać fragmentów w ten sposób.

CoolMind
źródło
-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
farid_z
źródło