Seguridad de tipos en Kotlin DSL y Navigation Compose

Puedes usar APIs integradas con seguridad de tipos para proporcionar seguridad de tipos en tiempo de compilación para tu gráfico de navegación. Estas APIs están disponibles cuando tu app usa el Navigation Compose o el Navigation Kotlin DSL. Están disponibles a partir de Navigation 2.8.0.

Estas APIs son equivalentes a lo que Safe Args proporciona a los gráficos de navegación compilados con XML.

Define rutas

Para usar rutas con seguridad de tipos en Compose, primero debes definir clases u objetos serializables que representen tus rutas.

Para definir objetos serializables, usa la anotación @Serializable que proporciona el complemento de serialización de Kotlin. Para agregar este complemento a tu proyecto, agrega estas dependencias.

Usa las siguientes reglas para decidir qué tipo usar para tu ruta:

  • Objeto: Usa un objeto para rutas sin argumentos.
  • Clase: Usa una clase o una clase de datos para rutas con argumentos.
  • KClass<T>: Úsala si no necesitas pasar argumentos, como una clase sin parámetros o una clase en la que todos los parámetros tienen valores predeterminados.
    1. Por ejemplo: Profile::class

En todos los casos, el objeto o la clase deben ser serializables.

Por ejemplo:

// 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)

Compila tu gráfico

A continuación, debes definir tu gráfico de navegación. Usa la composable() función para definir elementos componibles como destinos en tu gráfico de navegación.

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

Observa lo siguiente en este ejemplo:

  • composable() toma un parámetro de tipo. Es decir, composable<Profile>.
  • Definir el tipo de destino es un enfoque más sólido que pasar una route cadena como en composable("profile").
  • La clase de ruta define el tipo de cada argumento de navegación, como en val id: String, por lo que no es necesario NavArgument.
  • Para la ruta de perfil, el método de extensión toRoute() vuelve a crear el objeto Profile a partir de NavBackStackEntry y sus argumentos.

Para obtener más información sobre cómo diseñar tu gráfico en general, consulta la página Cómo diseñar tu gráfico de navegación.

Accede a los argumentos en un ViewModel

Para acceder a los argumentos desde una ruta con seguridad de tipos en un ViewModel, puedes recuperar la ruta desde el SavedStateHandle llamando a SavedStateHandle.toRoute<T>(), donde T es tu clase de ruta:

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

Por último, puedes navegar a tu elemento componible con la navigate() función pasando la instancia de la ruta:

navController.navigate(Profile(id = 123))

Esto lleva al usuario al destino composable<Profile> en el gráfico de navegación. Cualquier argumento de navegación, como id, se puede obtener reconstruyendo Profile con NavBackStackEntry.toRoute y leyendo sus propiedades.

Recursos adicionales