Segurança de tipo na DSL do Kotlin e no Navigation Compose

É possível usar APIs integradas com segurança de tipo para oferecer segurança de tipo no tempo de compilação para o gráfico de navegação. Essas APIs estão disponíveis quando o app usa o Navigation Compose ou a DSL de navegação do Kotlin. Elas estão disponíveis a partir de Navigation 2.8.0.

Essas APIs são equivalentes ao que o Safe Args oferece para gráficos de navegação criados usando XML.

Definir rotas

Para usar rotas com segurança de tipo no Compose, primeiro defina classes ou objetos serializáveis que representam suas rotas.

Para definir objetos serializáveis, use a anotação @Serializable fornecida pelo plug-in de serialização do Kotlin. Esse plug-in pode ser adicionado ao projeto com a inclusão destas dependências.

Use as regras a seguir para decidir qual tipo usar para sua rota:

  • Objeto: use um objeto para rotas sem argumentos.
  • Classe: use uma classe ou classe de dados para rotas com argumentos.
  • KClass<T>: use se não for necessário transmitir argumentos, como uma classe sem parâmetros ou uma classe em que todos os parâmetros têm valores padrão
    1. Por exemplo: Profile::class

Em todos os casos, o objeto ou a classe precisa ser serializável.

Por exemplo:

// Define a home route that doesn't take any arguments
@Serializable
object Home

// Define a profile route that takes an ID
@Serializable
data class Profile(val id: String)

Criar o gráfico

Em seguida, defina o gráfico de navegação. Use a composable() função para definir elementos combináveis como destinos no gráfico de navegação.

NavHost(navController, startDestination = Home) {
     composable<Home> {
         HomeScreen(onNavigateToProfile = { id ->
             navController.navigate(Profile(id))
         })
     }
     composable<Profile> { backStackEntry ->
         val profile: Profile = backStackEntry.toRoute()
         ProfileScreen(profile.id)
     }
}

Observe o seguinte neste exemplo:

  • composable() usa um parâmetro de tipo. Ou seja, composable<Profile>.
  • Definir o tipo de destino é uma abordagem mais robusta do que transmitir uma route string como em composable("profile").
  • A classe de rota define o tipo de cada argumento de navegação, como em val id: String, então não é necessário usar NavArgument.
  • Para a rota de perfil, o toRoute() método de extensão recria o Profile objeto da NavBackStackEntry e dos argumentos dele.

Para mais informações sobre como criar o gráfico em geral, consulte a página Projetar o gráfico de navegação.

Acessar argumentos em um ViewModel

Para acessar argumentos de uma rota com segurança de tipo em um ViewModel, recupere a rota da SavedStateHandle chamando SavedStateHandle.toRoute<T>(), em que T é a classe de rota:

class ProfileViewModel(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    private val profile = savedStateHandle.toRoute<Profile>()
    private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
}

Por fim, navegue até o elemento combinável usando a navigate() função transmitindo a instância da rota:

navController.navigate(Profile(id = 123))

Isso navega o usuário até o destino composable<Profile> no gráfico de navegação. Todos os argumentos de navegação, como id, podem ser obtidos reconstruindo Profile usando NavBackStackEntry.toRoute e lendo as propriedades dele.

Outros recursos