Transakcje z fragmentem kodu

W czasie działania FragmentManager w odpowiedzi na interakcję użytkownika może dodawać, usuwać i zastępować fragmenty oraz wykonywać na nich inne działania. Każdy przesyłany zestaw zmian fragmentów jest nazywany transakcją. Za pomocą interfejsów API dostarczanych przez klasę FragmentTransaction możesz określić, co ma się stać w obrębie transakcji. Możesz zgrupować wiele działań w jedną transakcję, na przykład transakcja może dodawać lub zastępować wiele fragmentów. Takie grupowanie może być przydatne, gdy wiele fragmentów równorzędnych jest wyświetlanych na tym samym ekranie, np. w widokach podzielonych.

Każdą transakcję możesz zapisać w stosie wstecznym zarządzanym przez FragmentManager, co pozwoli użytkownikowi przejść wstecz przez zmiany fragmentów – podobnie jak w przypadku przechodzenia wstecz po działaniach.

Instancję FragmentTransaction można pobrać z FragmentManager, wywołując beginTransaction(), jak w tym przykładzie:

Kotlin

val fragmentManager = ...
val fragmentTransaction = fragmentManager.beginTransaction()

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Ostatnie wywołanie każdego FragmentTransaction musi zatwierdzić transakcję. Wywołanie commit() sygnalizuje interfejs FragmentManager, że wszystkie operacje zostały dodane do transakcji.

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();

Zezwalaj na zmianę kolejności zmian stanu fragmentu

Każdy element FragmentTransaction powinien używać parametru setReorderingAllowed(true):

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

Java

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

Ze względu na zgodność działania flaga zmiany kolejności jest domyślnie wyłączona. Jest jednak wymagane, aby umożliwić FragmentManager prawidłowe wykonanie FragmentTransaction, zwłaszcza gdy działa ona na stosie wstecznym i uruchamia animacje oraz przejścia. Włączenie tej flagi daje pewność, że w przypadku jednoczesnego wykonywania wielu transakcji wszystkie fragmenty pośrednie (tj. te, które zostały dodane, a następnie natychmiast zastąpione) nie będą się zmieniać w cyklu życia ani nie będą wykonywane ich animacje lub przejścia. Pamiętaj, że ta flaga wpływa zarówno na początkowe wykonanie transakcji, jak i na cofanie transakcji z użyciem funkcji popBackStack().

Dodawanie i usuwanie fragmentów

Aby dodać fragment do FragmentManager, wywołaj metodę add() w transakcji. Ta metoda otrzymuje identyfikator kontenera dla danego fragmentu oraz nazwę klasy fragmentu, który chcesz dodać. Dodany fragment zostanie przeniesiony do stanu RESUMED. Zdecydowanie zalecamy, aby kontener był FragmentContainerView, który jest częścią hierarchii widoków.

Aby usunąć fragment z hosta, wywołaj metodę remove(), przekazując do instancji fragmentu pobranej z menedżera fragmentów za pomocą metody findFragmentById() lub findFragmentByTag(). Jeśli widok fragmentu został wcześniej dodany do kontenera, zostanie on z niego usunięty. Usunięty fragment jest przenoszony do stanu DESTROYED.

Za pomocą metody replace() możesz zastąpić istniejący fragment w kontenerze wystąpieniem nowej, podanej przez Ciebie klasy fragmentu. Wywołanie replace() jest równoważne wywołaniu remove() z fragmentem w kontenerze i dodaniu do tego samego kontenera nowego fragmentu.

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 nowe wystąpienie obiektu ExampleFragment zastępuje fragment, który znajduje się obecnie w kontenerze układu oznaczonym przez R.id.fragment_container.

Domyślnie zmiany wprowadzone w FragmentTransaction nie są dodawane do stosu wstecznego. Aby zapisać te zmiany, możesz wywołać metodę addToBackStack() w usłudze FragmentTransaction. Więcej informacji znajdziesz w sekcji Menedżer fragmentów.

Zatwierdzenie jest asynchroniczne

Wywołanie commit() nie przeprowadza transakcji od razu. Transakcja powinna być raczej uruchomiona w głównym wątku interfejsu, gdy tylko będzie to możliwe. W razie potrzeby możesz jednak od razu uruchomić transakcję dotyczącą fragmentu w wątku UI, używając wywołania commitNow().

Pamiętaj, że dyrektywa 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, używając wywołania executePendingTransactions(). Ta metoda jest zgodna z tymi zasadami: addToBackStack.

W większości przypadków wystarczy Ci commit().

Kolejność operacji jest istotna

Kolejność wykonywania operacji w obrębie FragmentTransaction jest istotna, zwłaszcza gdy korzystasz z setCustomAnimations(). Ta metoda stosuje podane animacje do wszystkich operacji na fragmentach, które po nich występują.

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()

Ogranicz cykl życia fragmentu

FragmentTransactions może wpływać na stan cyklu życia poszczególnych fragmentów dodanych w zakresie transakcji. Podczas tworzenia elementu FragmentTransaction setMaxLifecycle() ustawia maksymalny stan danego fragmentu. Na przykład ViewPager2 używa setMaxLifecycle(), aby ograniczać fragmenty poza ekranem do stanu STARTED.

Pokazywanie 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 ustawiają widoczność widoków fragmentu bez wpływu na cykl życia fragmentu.

Chociaż nie musisz używać transakcji na fragment do przełączania widoczności widoków w obrębie danego fragmentu, te metody są przydatne w przypadkach, gdy chcesz powiązać zmiany stanu widoczności z transakcjami w stosie wstecznym.

Dołączanie i odłączanie fragmentów

Metoda FragmentTransaction detach() odłącza fragment z interfejsu, niszcząc jego hierarchię widoków. Fragment pozostaje w tym samym stanie (STOPPED) co po umieszczeniu na stosie tylnym. Oznacza to, że dany fragment został usunięty z interfejsu, ale nadal jest zarządzany przez menedżera fragmentów.

Metoda attach() ponownie dołącza fragment, od którego został wcześniej odłączony. W ten sposób jej hierarchia widoków zostanie odtworzona, dołączona do interfejsu użytkownika i wyświetlona.

Gdy obiekt FragmentTransaction jest traktowany jako pojedynczy, niepodzielny zbiór operacji, wywołania detach i attach w tym samym wystąpieniu fragmentu w tej samej transakcji skutecznie anulują się wzajemnie, co pozwala uniknąć zniszczenia i natychmiastowego odtwarzania UI fragmentu. Jeśli chcesz odłączyć, a następnie natychmiast ponownie dołączyć fragment, użyj osobnych transakcji rozdzielonych znakiem executePendingOperations(), jeśli używasz atrybutu commit().