As seções a seguir descrevem estratégias para salvar a backstack e armazenar o estado associado às entradas nela.
Salvar a backstack
Garantir que o estado de navegação do app persista em vários eventos de ciclo de vida,
incluindo mudanças de configuração e encerramento do processo, é crucial para uma boa experiência
do usuário. No Navigation 3, você é responsável pela backstack, então não há diretrizes
estritas sobre como criar ou salvar. No entanto, o Navigation 3 oferece
um método de conveniência que fornece uma backstack que pode ser salva:
rememberNavBackStack.
Usar rememberNavBackStack
A função combinável rememberNavBackStack foi projetada para criar uma backstack
que persiste em mudanças de configuração e encerramentos de processos.
Para que o rememberNavBackStack funcione corretamente, cada chave na backstack
precisa atender a requisitos específicos:
- Implementar a interface
NavKey: cada chave na backstack precisa implementar a interfaceNavKey. Isso funciona como uma interface de marcador que sinaliza para a biblioteca que a chave pode ser salva. - Ter a anotação
@Serializable: além de implementarNavKey, as classes e os objetos de chave precisam ser marcados com a anotação@Serializable.
O snippet a seguir mostra uma implementação correta de rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
Lembrar uma backstack com subtipos de NavKey
A função combinável rememberNavBackStack retorna um NavBackStack<NavKey>.
Se o app definir o próprio subtipo de NavKey do qual todas as chaves
herdam, você poderá preservar essa digitação implementando uma função remember
personalizada, da seguinte maneira:
@Serializable sealed interface MyAppNavKey : NavKey @Serializable data object ScreenA: MyAppNavKey @Serializable data class ScreenB(val id: String): MyAppNavKey @Composable fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> { return rememberSerializable(serializer = serializer()) { NavBackStack(*elements) } } @Composable fun MyApp() { // defaultNavBackStack is NavBackStack<NavKey> val defaultNavBackStack = rememberNavBackStack(ScreenA) // myAppNavBackStack is NavBackStack<MyAppNavKey> val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA) }
Para mais exemplos, incluindo como lidar com polimorfismo aberto, consulte
NavBackStackSamples.
Alternativa: armazenamento em um ViewModel
Outra abordagem para gerenciar a backstack é armazená-la em um ViewModel.
Para persistência durante o encerramento do processo ao usar um ViewModel ou qualquer outro
armazenamento personalizado, é necessário:
- Verifique se as chaves são serializáveis: assim como em
rememberNavBackStack, as chaves de navegação precisam ser serializáveis. - Processar a serialização e a desserialização manualmente: você é responsável por
salvar manualmente a representação serializada de cada chave no armazenamento persistente (por exemplo,
SharedPreferences, um banco de dados ou um arquivo) e desserializá-la quando o app estiver em segundo plano ou sendo restaurado.
Como definir o escopo de instâncias de ViewModel para objetos NavEntry
ViewModels são usados para reter o estado relacionado à interface em mudanças de configuração,
como rotações de tela. Por padrão, os ViewModels têm como escopo o ViewModelStoreOwner mais próximo, que normalmente é o Activity ou o Fragment.
No entanto, talvez você queira definir o escopo de um ViewModel para um NavEntry específico (ou seja, uma
tela ou um destino específico) na backstack, em vez de todo o
Activity. Isso garante que o estado do ViewModel seja retido apenas enquanto
esse NavEntry específico fizer parte da backstack e seja limpo quando o
NavEntry for removido.
A biblioteca de complementos androidx.lifecycle:lifecycle-viewmodel-navigation3 oferece
um NavEntryDecorator que facilita isso. Esse decorador fornece um
ViewModelStoreOwner para cada NavEntry. Quando você cria um ViewModel dentro do conteúdo de um
NavEntry (por exemplo, usando viewModel() no Compose), ele é automaticamente
definido para a chave desse NavEntry específico na backstack. Isso significa que o
ViewModel é criado quando o NavEntry é adicionado à backstack e
limpo quando ele é removido.
Para usar NavEntryDecorator para definir o escopo de ViewModels para NavEntrys, siga
estas etapas:
- Adicione a dependência
androidx.lifecycle:lifecycle-viewmodel-navigation3ao arquivoapp/build.gradle.kts. - Adicione o
rememberSaveableStateHolderNavEntryDecorator()padrão à lista deentryDecoratorsao criar umNavDisplay. - Adicione
rememberViewModelStoreNavEntryDecorator()à lista deentryDecorators.
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSaveableStateHolderNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )