Transacciones de fragmentos

Durante el tiempo de ejecución, un FragmentManager puede agregar, quitar, reemplazar y realizar otras acciones con fragmentos en respuesta a la interacción del usuario. Cada conjunto de cambios de fragmento que confirmes se denomina transacción, y puedes especificar qué hacer dentro de la transacción mediante las API que proporciona la clase FragmentTransaction. Puedes agrupar varias acciones en una sola transacción; por ejemplo, una transacción puede agregar o reemplazar varios fragmentos. Esta agrupación puede ser útil para cuando se muestran varios fragmentos del mismo nivel en la misma pantalla, como en el caso de las vistas divididas.

Puedes guardar cada transacción en una pila de actividades administrada por el FragmentManager, lo que le permite al usuario navegar hacia atrás por los cambios realizados en el fragmento, de forma similar a navegar hacia atrás por las actividades.

Puedes obtener una instancia de FragmentTransaction desde el FragmentManager si llamas a beginTransaction(), como se muestra en el siguiente ejemplo:

Kotlin

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

Java

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

La llamada final en cada FragmentTransaction debe confirmar la transacción. La llamada commit() señala al FragmentManager que todas las operaciones se agregaron a la transacción.

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

Cómo permitir el reordenamiento de los cambios de estado de los fragmentos

Cada FragmentTransaction debe usar setReorderingAllowed(true):

Kotlin

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

Java

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

Para lograr la compatibilidad del comportamiento, la marca de orden no está habilitada de forma predeterminada. Sin embargo, es necesaria para permitir que FragmentManager ejecute correctamente tu FragmentTransaction, en especial cuando opera en la pila de actividades y ejecuta animaciones y transiciones. Habilitar la marca garantiza que, si se ejecutan varias transacciones, los fragmentos intermedios (es decir, los que se agregan y, luego, se reemplazan de inmediato) no experimenten cambios del ciclo de vida, y que sus animaciones o transiciones no se ejecuten. Ten en cuenta que esta marca afecta tanto la ejecución inicial de la transacción como la reversión de la transacción con popBackStack().

Cómo agregar y quitar fragmentos

Para agregar un fragmento a un FragmentManager, llama a add() en la transacción. Este método recibe el ID del contenedor del fragmento, así como el nombre de la clase del fragmento que deseas agregar. El fragmento agregado pasa al estado RESUMED. Te recomendamos que el contenedor sea una FragmentContainerView que forme parte de la jerarquía de vistas.

Para quitar un fragmento del host, llama a remove() y pasa una instancia de fragmento que se recuperó del administrador de fragmentos a través de findFragmentById() o findFragmentByTag(). Si previamente se agregó la vista del fragmento a un contenedor, la vista se quitará del contenedor en este momento. El fragmento que se quita pasa al estado DESTROYED.

Usa replace() para reemplazar un fragmento existente en un contenedor por una instancia de la nueva clase de fragmento que proporciones. Llamar a replace() equivale a llamar a remove() con un fragmento en un contenedor y agregar un fragmento nuevo al mismo contenedor.

En el siguiente fragmento de código, se muestra cómo puedes reemplazar un fragmento por otro:

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

En este ejemplo, una instancia nueva de ExampleFragment reemplaza el fragmento, si hay alguno, que se encuentra en ese momento en el contenedor de diseño identificado por R.id.fragment_container.

De forma predeterminada, los cambios realizados en una FragmentTransaction no se agregan a la pila de actividades. Para guardar esos cambios, puedes llamar a addToBackStack() en la FragmentTransaction. Si deseas obtener más información, consulta el administrador de fragmentos.

La confirmación es asíncrona

Llamar a commit() no realiza la transacción inmediatamente. En cambio, la transacción se programará para ejecutarse en el subproceso de IU principal en cuanto pueda hacerlo. Sin embargo, si es necesario, puedes llamar a commitNow() a fin de ejecutar la transacción del fragmento en tu subproceso de IU de inmediato.

Ten en cuenta que commitNow no es compatible con addToBackStack. Como alternativa, puedes ejecutar todas las FragmentTransactions pendientes enviadas por las llamadas de commit() aún no ejecutadas llamando a executePendingTransactions(). Este enfoque es compatible con addToBackStack.

Para la gran mayoría de los casos de uso, solo necesitas commit().

El orden de las operaciones es significativo

El orden en el que realizas operaciones en una FragmentTransaction es significativo, en especial cuando se usa setCustomAnimations(). Este método aplica las animaciones determinadas a todas las operaciones de fragmentos que la siguen.

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

Cómo limitar el ciclo de vida del fragmento

FragmentTransactions puede afectar el estado del ciclo de vida de los fragmentos individuales agregados dentro del alcance de la transacción. Cuando creas una FragmentTransaction, setMaxLifecycle() establece un estado máximo para el fragmento determinado. Por ejemplo, ViewPager2 usa setMaxLifecycle() a fin de limitar los fragmentos fuera de la pantalla al estado STARTED.

Cómo mostrar y ocultar vistas de fragmentos

Usa los métodos show() y hide() de FragmentTransaction para mostrar y ocultar la vista de fragmentos agregados a un contenedor. Estos métodos establecen la visibilidad de las vistas del fragmento sin afectar el ciclo de vida de este.

Si bien no necesitas usar una transacción de fragmento para activar o desactivar la visibilidad de las vistas dentro de un fragmento, estos métodos resultan útiles en casos en los que quieres que se asocien los cambios del estado de visibilidad con las transacciones en la pila de actividades.

Cómo conectar y desconectar fragmentos

El método detach() de FragmentTransaction desvincula el fragmento de la IU, lo que destruye su jerarquía de vistas. El fragmento permanece en el mismo estado (STOPPED) que tenía cuando se coloca en la pila de actividades. Esto significa que se quitó el fragmento de la IU, pero aún lo administra el administrador de fragmentos.

El método attach() vuelve a conectar un fragmento que se había desconectado con anterioridad. Esto hace que su jerarquía de vistas se vuelva a crear, se conecte a la IU y se muestre.

Dado que una FragmentTransaction se trata como un conjunto único de operaciones atómicas, las llamadas a detach y attach en la misma instancia del fragmento y en la misma transacción se cancelan entre sí. De esta manera, evitan la destrucción de la IU del fragmento y su inmediata recreación. Si deseas desconectar y, luego, reconectar un fragmento, usa transacciones independientes, separadas por executePendingOperations() si usas commit().