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 do ciclo de vida, incluindo mudanças de configuração e encerramento do processo, é fundamental para uma boa experiência do usuário. Na navegação 3, você é o proprietário da backstack. Portanto, não há diretrizes rigorosas sobre como criar ou salvar. No entanto, a navegação 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 persista em mudanças de configuração e encerramento do processo.
Para que rememberNavBackStack funcione corretamente, cada chave na backstack precisa obedecer a requisitos específicos:
- Implementar a interface
NavKey: cada chave na backstack precisa implementar a interfaceNavKey. Ela 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 de memorização 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 processar o polimorfismo aberto, consulte
NavBackStackSamples.
Alternativa: armazenar 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, você precisa:
- Garantir que as chaves sejam serializáveis: assim como com
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 e
desserializá-la do armazenamento persistente (por exemplo,
SharedPreferences, um banco de dados ou um arquivo) quando o app está sendo colocado em segundo plano ou sendo restaurado.
Definir o escopo de ViewModels para NavEntrys
Os ViewModels são usados para manter o estado relacionado à interface em mudanças de configuração, como rotações de tela. Por padrão, os ViewModels são definidos como o ViewModelStoreOwner mais próximo, que normalmente é sua Activity ou Fragment.
No entanto, talvez você queira definir o escopo de um ViewModel para uma NavEntry específica (ou seja, uma tela ou destino específico) na backstack, em vez de toda a Activity. Isso garante que o estado do ViewModel seja mantido apenas enquanto essa NavEntry específica fizer parte da backstack e seja limpo quando a NavEntry for removida.
A biblioteca complementar androidx.lifecycle:lifecycle-viewmodel-navigation3 fornece
um NavEntryDecorator que facilita isso. Esse decorador fornece um ViewModelStoreOwner para cada NavEntry. Quando você cria um ViewModel dentro do conteúdo de uma NavEntry (por exemplo, usando viewModel() no Compose), ele é automaticamente definido como a chave dessa NavEntry específica na backstack. Isso significa que o ViewModel é criado quando a NavEntry é adicionada à backstack e limpa quando é removida.
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 padrão
rememberSaveableStateHolderNavEntryDecorator()à lista deentryDecoratorsao construir 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 { }, )