W czasie wykonywania kodu FragmentManager
może on dodawać, usuwać i zastępować fragmenty oraz wykonywać inne działania w odpowiedzi na interakcje użytkownika. Każdy zestaw zmian fragmentu, który zatwierdzisz, nazywa się transakcją. Możesz określić, co ma się dziać w ramach transakcji, korzystając z interfejsów API udostępnionych przez klasę FragmentTransaction
. W jednej transakcji możesz zgrupować wiele działań – na przykład transakcja może dodać lub zastąpić wiele fragmentów. Takie grupowanie może być przydatne, gdy na tym samym ekranie wyświetla się kilka elementów wyższego rzędu, np. w przypadku widoku podzielonego.
Każdą transakcję możesz zapisać w steku zarządzania FragmentManager
, aby umożliwić użytkownikowi cofanie się do poprzednich zmian w fragmentach – podobnie jak w przypadku czynności.
Możesz uzyskać instancję FragmentTransaction
z FragmentManager
, wywołując funkcję beginTransaction()
, jak pokazano w tym przykładzie:
Kotlin
val fragmentManager = ... val fragmentTransaction = fragmentManager.beginTransaction()
Java
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Ostatnie wywołanie w każdym FragmentTransaction
musi zatwierdzić transakcję.
Wywołanie commit()
sygnalizuje FragmentManager
, że do transakcji zostały dodane wszystkie operacje.
Kotlin
val fragmentManager = ... // The fragment-ktx module provides a commit block that automatically // calls beginTransaction and commit for you. fragmentManager.commit { // Add operations here }
Java
FragmentManager fragmentManager = ... FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // Add operations here fragmentTransaction.commit();
Zezwalanie na zmianę kolejności zmian stanu fragmentu
Każdy FragmentTransaction
powinien używać setReorderingAllowed(true)
:
Kotlin
supportFragmentManager.commit { ... setReorderingAllowed(true) }
Java
FragmentManager fragmentManager = ... fragmentManager.beginTransaction() ... .setReorderingAllowed(true) .commit();
Ze względu na zgodność zachowania domyślnie nie jest włączona flaga przetasowania.
Konieczne jest jednak, aby FragmentManager
mógł prawidłowo wykonywać FragmentTransaction
, zwłaszcza gdy działa na wyższym poziomie stosu oraz uruchamia animacje i przejścia. Włączenie tej opcji powoduje, że jeśli wiele transakcji jest wykonywanych jednocześnie, żadne fragmenty pośrednie (czyli te, które są dodawane, a następnie natychmiast zastępowane) nie przechodzą przez zmiany cyklu życia ani nie są animowane ani przekształcane. Pamiętaj, że ta flaga wpływa zarówno na początkowe wykonanie transakcji, jak i na cofnięcie transakcji z popBackStack()
.
Dodawanie i usuwanie fragmentów
Aby dodać fragment do FragmentManager
, wywołaj funkcję add()
w ramach transakcji. Ta metoda otrzymuje identyfikator kontenera fragmentu oraz nazwę klasy fragmentu, który chcesz dodać. Dodany fragment zostanie przeniesiony do stanu RESUMED
. Zdecydowanie zalecamy, aby kontener był elementem FragmentContainerView
, który jest częścią hierarchii widoków.
Aby usunąć fragment z serwera, wywołaj funkcję remove()
, podając instancję fragmentu, który został pobrany z menedżera fragmentów za pomocą funkcji findFragmentById()
lub findFragmentByTag()
.
Jeśli widok fragmentu został wcześniej dodany do kontenera, zostanie z niego usunięty. Usunięty fragment zostaje przeniesiony do stanu DESTROYED
.
Użyj polecenia replace()
, aby zastąpić istniejący fragment w kontenerze instancją nowej klasy fragmentu podanej przez Ciebie. Wywołanie funkcji replace()
jest równoważne wywołaniu funkcji remove()
z fragmentem w kontenerze i dodaniem nowego fragmentu do tego samego kontenera.
Ten fragment kodu pokazuje, jak zastąpić jeden fragment innym:
Kotlin
// Create new fragment val fragmentManager = // ... // Create and commit a new transaction fragmentManager.commit { setReorderingAllowed(true) // Replace whatever is in the fragment_container view with this fragment replace<ExampleFragment>(R.id.fragment_container) }
Java
// Create new fragment and transaction FragmentManager fragmentManager = ... FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.setReorderingAllowed(true); // Replace whatever is in the fragment_container view with this fragment transaction.replace(R.id.fragment_container, ExampleFragment.class, null); // Commit the transaction transaction.commit();
W tym przykładzie nowy element ExampleFragment
zastępuje fragment,
jeśli taki istnieje, który znajduje się obecnie w kontenerze układu zidentyfikowanym przez
R.id.fragment_container
.
Domyślnie zmiany wprowadzone w FragmentTransaction
nie są dodawane do stosu wstecz. Aby zapisać te zmiany, możesz wywołać funkcję addToBackStack()
w obiekcie FragmentTransaction
. Więcej informacji znajdziesz w artykule Menedżer fragmentów.
Commit jest asynchroniczny
Wywołanie commit()
nie spowoduje natychmiastowego wykonania transakcji. Zamiast tego jest zaplanowana data uruchomienia transakcji w głównym wątku UI, gdy tylko będzie to możliwe. Jeśli jednak jest to konieczne, możesz wywołać metodę commitNow()
, by od razu uruchomić transakcję dotyczącą fragmentu w wątku interfejsu.
Pamiętaj, że commitNow
jest niezgodna z addToBackStack
. Możesz też wykonać wszystkie oczekujące wywołania FragmentTransactions
przesłane przez wywołania commit()
, które nie zostały jeszcze uruchomione, wywołując funkcję executePendingTransactions()
. To podejście jest zgodne z funkcją addToBackStack
.
W większości przypadków wystarczy commit()
.
kolejność wykonywania operacji ma znaczenie;
Kolejność wykonywania operacji w FragmentTransaction
ma znaczenie, zwłaszcza podczas korzystania z funkcji setCustomAnimations()
. Ta metoda stosuje określone animacje do wszystkich operacji fragmentu, które następują po niej.
Kotlin
supportFragmentManager.commit { setCustomAnimations(enter1, exit1, popEnter1, popExit1) add<ExampleFragment>(R.id.container) // gets the first animations setCustomAnimations(enter2, exit2, popEnter2, popExit2) add<ExampleFragment>(R.id.container) // gets the second animations }
Java
getSupportFragmentManager().beginTransaction() .setCustomAnimations(enter1, exit1, popEnter1, popExit1) .add(R.id.container, ExampleFragment.class, null) // gets the first animations .setCustomAnimations(enter2, exit2, popEnter2, popExit2) .add(R.id.container, ExampleFragment.class, null) // gets the second animations .commit()
Ograniczanie cyklu życia fragmentu
FragmentTransactions
może wpływać na stan cyklu życia poszczególnych fragmentów dodanych w ramach transakcji. Podczas tworzenia FragmentTransaction
,
setMaxLifecycle()
określa maksymalny stan danego fragmentu. Na przykład komponent ViewPager2
używa elementu setMaxLifecycle()
, aby ograniczyć fragmenty poza ekranem do stanu STARTED
.
Wyświetlanie i ukrywanie widoków fragmentu
Użyj metod FragmentTransaction
show()
i
hide()
, aby wyświetlać i ukrywać widok fragmentów dodanych do kontenera.
Te metody określają widoczność widoków fragmentu bez wpływania na cykl życia fragmentu.
Nie musisz używać transakcji fragmentu, aby przełączać widoczność widoków w fragmentach, ale te metody są przydatne w przypadkach, gdy chcesz, aby zmiany stanu widoczności były powiązane z transakcjami w dolnej części stosu.
Podłączanie i odłączanie fragmentów
Metoda FragmentTransaction
detach()
odłącza fragment od interfejsu, niszcząc jego hierarchię widoku. Fragment pozostaje w tym samym stanie (STOPPED
) co po umieszczeniu na stosu z tyłu.
Oznacza to, że fragment został usunięty z interfejsu, ale nadal jest zarządzany przez menedżera fragmentów.
Metoda attach()
ponownie przyłącza fragment, z którego został wcześniej odłączony.
Powoduje to odtworzenie hierarchii widoku, dołączenie jej do interfejsu użytkownika i wyświetlenie.
Ponieważ FragmentTransaction
jest traktowany jako pojedynczy nierozerwalny zestaw operacji, wywołania detach
i attach
w ramach tej samej transakcji skutecznie się wzajemnie anulują, co pozwala uniknąć zniszczenia i natychmiastowego odtworzenia interfejsu fragmentu. Jeśli chcesz odłączyć fragment, a następnie natychmiast go ponownie dołączyć, użyj oddzielnych transakcji rozdzielonych znakiem executePendingOperations()
(jeśli używasz znaku commit()
).