Fragment transactions

At runtime, a FragmentManager can add, remove, replace, and perform other actions with fragments in response to user interaction. Each set of fragment changes that you commit is called a transaction, and you can specify what to do inside the transaction using the APIs provided by the FragmentTransaction class. You can group multiple actions into a single transaction—for example, a transaction can add or replace multiple fragments. This grouping can be useful for when you have multiple sibling fragments displayed on the same screen, such as with split views.

You can save each transaction to a back stack managed by the FragmentManager, allowing the user to navigate backward through the fragment changes—similar to navigating backward through activities.

You can get an instance of FragmentTransaction from the FragmentManager by calling beginTransaction(), as shown in the following example:

Kotlin

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

Java

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

The final call on each FragmentTransaction must commit the transaction. The commit() call signals to the FragmentManager that all operations have been added to the transaction.

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

Allow reordering of fragment state changes

Each FragmentTransaction should use setReorderingAllowed(true):

Kotlin

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

Java

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

For behavior compatibility, the reordering flag is not enabled by default. It is required, however, to allow FragmentManager to properly execute your FragmentTransaction, particularly when it operates on the back stack and runs animations and transitions. Enabling the flag ensures that if multiple transactions are executed together, any intermediate fragments (i.e. ones that are added and then immediately replaced) do not go through lifecycle changes or have their animations or transitions executed. Note that this flag affects both the initial execution of the transaction and reversing the transaction with popBackStack().

Adding and removing fragments

To add a fragment to a FragmentManager, call add() on the transaction. This method receives the ID of the container for the fragment, as well as the class name of the fragment you wish to add. The added fragment is moved to the RESUMED state. It is strongly recommended that the container is a FragmentContainerView that is part of the view hierarchy.

To remove a fragment from the host, call remove(), passing in a fragment instance that was retrieved from the fragment manager through findFragmentById() or findFragmentByTag(). If the fragment's view was previously added to a container, the view is removed from the container at this point. The removed fragment is moved to the DESTROYED state.

Use replace() to replace an existing fragment in a container with an instance of a new fragment class that you provide. Calling replace() is equivalent to calling remove() with a fragment in a container and adding a new fragment to that same container.

The following code snippet shows how you can replace one fragment with another:

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

In this example, a new instance of ExampleFragment replaces the fragment, if any, that is currently in the layout container identified by R.id.fragment_container.

By default, the changes made in a FragmentTransaction are not added to the back stack. To save those changes, you can call addToBackStack() on the FragmentTransaction. For more information, see Fragment manager.

Commit is asynchronous

Calling commit() doesn't perform the transaction immediately. Rather, the transaction is scheduled to run on the main UI thread as soon as it is able to do so. If necessary, however, you can call commitNow() to run the fragment transaction on your UI thread immediately.

Note that commitNow is incompatible with addToBackStack. Alternatively, you can execute all pending FragmentTransactions submitted by commit() calls that have not yet run by calling executePendingTransactions(). This approach is compatible with addToBackStack.

For the vast majority of use cases, commit() is all you need.

Operation ordering is significant

The order in which you perform operations within a FragmentTransaction is significant, particularly when using setCustomAnimations(). This method applies the given animations to all fragment operations that follow it.

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

Limit the fragment's lifecycle

FragmentTransactions can affect the lifecycle state of individual fragments added within the scope of the transaction. When creating a FragmentTransaction, setMaxLifecycle() sets a maximum state for the given fragment. For example, ViewPager2 uses setMaxLifecycle() to limit the off-screen fragments to the STARTED state.

Showing and hiding fragment's views

Use the FragmentTransaction methods show() and hide() to show and hide the view of fragments that have been added to a container. These methods set the visibility of the fragment's views without affecting the lifecycle of the fragment.

While you don't need to use a fragment transaction to toggle the visibility of the views within a fragment, these methods are useful for cases where you want changes to the visibility state to be associated with transactions on the back stack.

Attaching and detaching fragments

The FragmentTransaction method detach() detaches the fragment from the UI, destroying its view hierarchy. The fragment remains in the same state (STOPPED) as when it is put on the back stack. This means that the fragment was removed from the UI but is still managed by the fragment manager.

The attach() method reattaches a fragment from which it was previously detached. This causes its view hierarchy to be recreated, attached to the UI, and displayed.

As a FragmentTransaction is treated as a single atomic set of operations, calls to both detach and attach on the same fragment instance in the same transaction effectively cancel each other out, thus avoiding the destruction and immediate recreation of the fragment's UI. Use separate transactions, separated by executePendingOperations() if using commit(), if you want to detach and then immediately re-attach a fragment.