O NavController
tem uma "backstack" que contém os destinos que o
usuário visitou. À medida que o usuário navega para outras telas no app, o
NavController
adiciona destinos à backstack e os remove dela.
Dentro da pilha, a backstack é uma estrutura de dados "último a chegar, primeiro a sair".
Portanto, o NavController
envia itens para a pilha e exibe os itens da parte de cima
dela.
Comportamento básico
Estes são os principais fatos que você precisa considerar sobre o comportamento da backstack:
- Primeiro destino: quando o usuário abre o app, o
NavController
envia o primeiro destino para a parte de cima da backstack. - Enviar para a pilha: cada chamada
NavController.navigate()
envia o destino especificado para a parte de cima da pilha. - Abrir o destino superior: tocar em Up ou Back chama os métodos
NavController.navigateUp()
eNavController.popBackStack()
, respectivamente. Eles retiram o destino superior da pilha. Consulte a página Princípios de navegação para mais informações sobre a diferença entre Up e Back.
Retornar
O método NavController.popBackStack()
tenta retirar o destino atual
da backstack e navegar para o destino anterior. Isso
faz com que o usuário volte uma etapa no histórico de navegação. O método retorna
um booleano indicando se ele retornou para o destino.
Retornar para um destino específico
Você também pode usar popBackStack()
para navegar a um destino específico. Para isso,
use uma das sobrecargas dele. Há várias que permitem transmitir um
identificador, como um id
inteiro ou uma string route
. Essas sobrecargas levam
o usuário ao destino associado ao identificador fornecido. Elas destacam tudo que está acima desse destino na pilha.
Essas sobrecargas também usam um booleano inclusive
. Ele determina se o
NavController
também precisa retirar o destino especificado da backstack
depois de ter navegado até ele.
Confira este breve exemplo:
navController.popBackStack(R.id.destinationId, true)
Aqui o NavController
retorna ao destino com o ID de número inteiro
destinationId
. Como o valor do argumento inclusive
é true
, o
NavController
também exibe o destino especificado da backstack.
Processar um retorno com falha
Quando popBackStack()
retornar false
, uma chamada subsequente para NavController.getCurrentDestination()
retornará null
. Isso significa que o app
retirou o último destino da backstack. Nesse caso, o usuário recebe
apenas uma tela em branco.
Isso pode ocorrer nos seguintes casos:
popBackStack()
não exibiu nada da pilha.popBackStack()
retirou um destino da backstack, e a pilha agora está vazia.
Para resolver isso, navegue até um novo destino ou chame finish()
na atividade para encerrar. O snippet a seguir demonstra isso:
kotlin
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish()
}
java
...
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish();
}
Abrir um destino
Para remover destinos da backstack ao navegar de um destino
para outro, adicione um argumento popUpTo()
à chamada de função
navigate()
associada. popUpTo()
instrui a biblioteca de navegação a remover alguns destinos
da backstack como parte da chamada para navigate()
. O valor do parâmetro é
o identificador de um destino na backstack. O identificador pode ser um
id
inteiro ou uma string route
.
Você pode incluir um argumento para o parâmetro inclusive
com um valor de true
para indicar que o destino especificado em popUpTo()
também deve
ser retirado da backstack.
Para implementar isso de forma programática, transmita popUpTo()
para navigate()
como parte de
NavOptions
com inclusive
definido como true
. Isso funciona no Compose e
no Views.
Salvar o estado ao usar a opção de abrir um destino
Ao usar popUpTo
para navegar até um destino, você pode, opcionalmente, salvar os
estados de todos os destinos retirados da backstack.
Para ativar essa opção, defina popUpToSaveState
como true
na action
associada
ou chame para NavController.navigate()
.
Ao navegar até um destino, você também pode definir restoreSaveState
como
true
para restaurar automaticamente o estado associado ao destino na
propriedade destination
.
Exemplo em XML
Confira um exemplo de popUpTo
em XML com uma ação:
<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"/>
Exemplos no Compose
Confira a seguir um exemplo completo do mesmo recurso no Compose:
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = "destination_a"
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable("destination_a") {
DestinationA(
onNavigateToB = {
// 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") {
inclusive = true
saveState = true
}
}
},
)
}
composable("destination_b") { DestinationB(/* ... */) }
}
}
@ Composable
fun DestinationA(onNavigateToB: () -> Unit) {
Button(onClick = onNavigateToB) {
Text("Go to A")
}
}
Mais detalhadamente, você pode mudar a forma como chama NavController.navigate()
das
seguintes maneiras:
// 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
}
Para informações gerais sobre como transmitir opções para NavController.navigate()
, consulte
o Guia de navegação com opções.
Destacar usando ações
Ao navegar usando uma ação, você também pode retirar destinos adicionais da backstack. Por exemplo, se o app tiver um fluxo de login inicial, assim que um usuário tiver feito login, todos os destinos relacionados ao login precisarão ser retirados da backstack para que o botão" "Voltar" não retorne os usuários ao fluxo de login.
Leitura adicional
Para mais informações, confira as seguintes páginas:
- Navegação circular: aprenda a evitar uma backstack sobrecarregada nos casos em que os fluxos de navegação são circulares.
- Destinos da caixa de diálogo: leia sobre como os destinos da caixa de diálogo introduzem considerações exclusivas sobre como gerenciar a backstack.