Salvar e gerenciar o estado de navegação

As seções a seguir descrevem estratégias para salvar a backstack e armazenar o estado associado às entradas na backstack.

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 de processo, é crucial para uma boa experiência do usuário. No Navigation 3, você é dono da sua backstack, então não há diretrizes rígidas sobre como criá-la ou salvá-la. No entanto, o Navigation 3 oferece um método de conveniência que fornece uma backstack salvável: rememberNavBackStack.

Usar rememberNavBackStack

A função combinável rememberNavBackStack foi projetada para criar uma backstack que persiste em mudanças de configuração e na interrupção do processo.

Para que rememberNavBackStack funcione corretamente, cada chave na backstack precisa obedecer a requisitos específicos:

  • Implementar a interface NavKey: todas as chaves na backstack precisam implementar a interface NavKey. 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 implementar NavKey, as classes e os objetos principais 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)
}

Alternativa: armazenamento em um ViewModel

Outra abordagem para gerenciar a backstack é armazená-la em um ViewModel. Para manter a persistência após a interrupção do processo ao usar um ViewModel ou qualquer outro armazenamento personalizado, faça o seguinte:

  • Verifique se as chaves são serializáveis: assim como no rememberNavBackStack, as chaves de navegação precisam ser serializáveis.
  • Processar a serialização e desserialização manualmente: você é responsável por salvar manualmente a representação serializada de cada chave no armazenamento persistente e desserializá-la (por exemplo, SharedPreferences, um banco de dados ou um arquivo) quando o app for para segundo plano ou for restaurado.

Como definir o escopo de ViewModels para NavEntrys

ViewModels são usados para manter o estado relacionado à interface em todas as mudanças de configuração, como a rotação da tela. Por padrão, ViewModels são aplicados ao ViewModelStoreOwner mais próximo, que normalmente é o Activity ou Fragment.

No entanto, talvez você queira definir o escopo de uma 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 da ViewModel seja mantido apenas enquanto essa NavEntry específica faz parte da backstack e é limpa quando a NavEntry é aberta.

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 limitado à chave específica do NavEntry na backstack. Isso significa que o ViewModel é criado quando o NavEntry é adicionado à backstack e limpo quando é removido.

Para usar NavEntryDecorator para definir o escopo de ViewModels para NavEntrys, siga estas etapas:

  1. Adicione a dependência androidx.lifecycle:lifecycle-viewmodel-navigation3 ao arquivo app/build.gradle.kts.
  2. Adicione rememberSavedStateNavEntryDecorator() à lista de entryDecorators ao criar um NavDisplay.
  3. Adicione outros decoradores ao NavDisplay.

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSceneSetupNavEntryDecorator(),
        rememberSavedStateNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)