NavController
contiene una "pila de actividades". que contiene los destinos a los que el usuario
ha visitado. A medida que el usuario navega a través de las pantallas de tu app, NavController
agrega y quita destinos hacia y desde la pila de actividades.
Debido a su naturaleza, la pila de actividades es una estructura de datos del tipo "último en entrar, primero en salir". El
Por lo tanto, NavController
envía elementos y los muestra en la parte superior de la
en una pila.
Comportamiento básico
A continuación, se enumeran los datos principales que debes considerar sobre el comportamiento de la pila de actividades:
- Primer destino: Cuando el usuario abre la app,
NavController
envía el primer destino a la parte superior de la pila de actividades. - Envío a la pila: Cada llamada
NavController.navigate()
envía el destino determinado a la parte superior de la pila. - Destino principal emergente: Si presionas Up o Back, se llama a
NavController.navigateUp()
yNavController.popBackStack()
, respectivamente. Se quita el destino superior de la pila. Consulta la página Principios de Navigation para obtener más información sobre la diferencia entre Up y Back.
Retroceso
El método NavController.popBackStack()
intenta quitar el destino actual de la pila de actividades y navegar al destino anterior. De este modo, el usuario retrocede un paso en su historial de navegación. Muestra un valor booleano que indica si volvió a aparecer en el destino.
Retroceso a un destino específico
También puedes usar popBackStack()
para navegar a un destino específico. Para hacerlo, usa una de sus sobrecargas. Hay varios que te permiten pasar un identificador, como un id
entero o una cadena route
. Estas sobrecargas llevan al usuario al destino asociado con el identificador determinado. Lo más importante es que muestran todo en la pila encima de ese destino.
Estas sobrecargas también toman un valor booleano inclusive
. Determina si NavController
también debe quitar el destino especificado de la pila de actividades después de haber navegado hacia él.
Observa este breve fragmento de ejemplo:
navController.popBackStack(R.id.destinationId, true)
Aquí, NavController
vuelve al destino con el ID de número entero destinationId
. Como el valor del argumento inclusive
es true
, NavController
también muestra el destino determinado de la pila de actividades.
Qué hacer ante un retroceso fallido
Cuando popBackStack()
muestra false
, una llamada posterior a NavController.getCurrentDestination()
muestra el valor null
. Esto significa que la app quitó el último destino de la pila de actividades. En este caso, el usuario solo ve
una pantalla en blanco.
Esto puede suceder en los siguientes casos:
popBackStack()
no mostró ningún elemento de la pila.popBackStack()
quitó un destino de la pila de actividades, y la pila ahora está vacía.
Para resolverlo, debes navegar a un destino nuevo o llamar a finish()
en tu actividad para finalizarlo. Esto se demuestra en el siguiente fragmento:
Kotlin
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish()
}
Java
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish();
}
Navegación a un destino
Para quitar destinos de la pila de actividades cuando navegas de un destino a otro, agrega un argumento popUpTo()
a la llamada de la función navigate()
asociada. popUpTo()
indica a la biblioteca de Navigation que quite algunos destinos de la pila de actividades como parte de la llamada a navigate()
. El valor del parámetro es el identificador de un destino en la pila de actividades. El identificador puede ser un número entero id
o una cadena route
.
Puedes incluir un argumento para el parámetro inclusive
con un valor de true
para indicar que el destino que especificaste en popUpTo()
también debería salir de la pila de actividades.
Para implementar esto de manera programática, pasa popUpTo()
a navigate()
como parte de NavOptions
con inclusive
configurado como true
. Esto funciona tanto en Compose como en View.
Guardado de un estado de apertura
Cuando usas popUpTo
para navegar a un destino, tienes la opción de guardar el
y los estados de todos los destinos
se quitaron de la pila de actividades. Puedes
Luego, restablece la pila de actividades y los destinos cuando navegues a ese destino.
en otro momento. Esto te permite preservar el estado de un destino determinado y tener
varias pilas de actividades.
Para hacerlo de manera programática, especifica saveState = true
cuando agregues popUpTo
a
tus opciones de navegación.
También puedes especificar restoreState = true
en tus opciones de navegación para
restablecer automáticamente la pila de actividades y el estado asociado con la
destino.
Por ejemplo:
navController.navigate(
route = route,
navOptions = navOptions {
popUpTo<A>{ saveState = true }
restoreState = true
}
)
Para poder guardar y restablecer el estado en XML, define popUpToSaveState
como true
.
y restoreState
como true
, respectivamente, en el action
asociado.
Ejemplo de XML
Aquí tienes un ejemplo de popUpTo
en XML con una acción:
<action
android:id="@+id/action_a_to_b"
app:destination="@id/b"
app:popUpTo="@+id/a"
app:popUpToInclusive="true"
app:restoreState=”true”
app:popUpToSaveState="true"/>
Ejemplo de Compose
El siguiente es un ejemplo completo de lo mismo en Compose:
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: Any = A
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable<A> {
DestinationA(
onNavigateToB = {
// Pop everything up to, and including, the A destination off
// the back stack, saving the back stack and the state of its
// destinations.
// Then restore any previous back stack state associated with
// the B destination.
// Finally navigate to the B destination.
navController.navigate(route = B) {
popUpTo<A> {
inclusive = true
saveState = true
}
restoreState = true
}
},
)
}
composable<B> { DestinationB(/* ... */) }
}
}
@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
Button(onClick = onNavigateToB) {
Text("Go to A")
}
}
De forma más detallada, puedes cambiar el modo en que llamas a NavController.navigate()
, como se muestra a continuación:
// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
popUpTo("destination_a")
}
// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
popUpTo("destination_a") { inclusive = true }
}
// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
launchSingleTop = true
}
Si deseas obtener información general para pasar opciones a NavController.navigate()
, consulta la guía de Navegación con opciones.
Navegación con acciones
Cuando navegas con una acción, puedes elegir quitar destinos adicionales de la pila de actividades. Por ejemplo, si tu app tiene un flujo de acceso inicial, una vez que un usuario accede, debes quitar todos los destinos relacionados con el acceso en la pila de actividades para que el botón Atrás no vuelva a dirigir a los usuarios al flujo de acceso.
Lectura adicional
Para obtener más información, consulta las siguientes páginas:
- Navegación circular: Obtén información para evitar una pila de actividades sobrecargada en casos en los que los flujos de navegación sean circulares.
- Destinos de diálogo: Obtén información sobre el modo en que los destinos de diálogo introducen consideraciones únicas para administrar la pila de actividades.