Kotlin DSL 和 Navigation Compose 中的类型安全

您可以使用内置的类型安全 API 为导航图提供编译时类型安全。当您的应用使用 Navigation Compose 或 Navigation Kotlin DSL 时,这些 API 可供使用。这些功能自 Navigation 2.8.0 起提供。

这些 API 相当于 Safe Args 为使用 XML 构建的导航图提供的功能。

定义路由

如需在 Compose 中使用类型安全的路由,您首先需要定义表示路由的可序列化类或对象。

如需定义可序列化的对象,请使用 Kotlin 序列化插件提供的 @Serializable 注解。您可以通过添加这些依赖项将此插件添加到项目中。

请按照以下规则确定要为路线使用哪种类型:

  • 对象:使用对象表示不带实参的路由。
  • 类:对于带有实参的路线,请使用类或数据类。
  • KClass<T>:如果您不需要传递实参,例如无参数的类或所有形参都有默认值的类,请使用此方法
    1. 例如:Profile::class

在所有情况下,对象或类都必须可序列化。

例如:

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

构建图表

接下来,您需要定义导航图。使用 composable() 函数将可组合项定义为导航图中的目的地。

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

在此示例中,请注意以下几点:

  • composable() 接受一个类型形参。即 composable<Profile>。
  • 与在 composable("profile") 中传递 route 字符串相比,定义目的地类型是一种更可靠的方法。
  • 路线类定义了每个导航实参的类型(如 val id: String 中所示),因此无需使用 NavArgument。
  • 对于个人资料路由,toRoute() 扩展方法会根据 NavBackStackEntry 及其参数重新创建 Profile 对象。

如需详细了解如何设计图表,请参阅设计导航图页面。

在 ViewModel 中访问实参

如需在 ViewModel 中访问类型安全的路由中的实参,您可以通过调用 SavedStateHandle.toRoute<T>() 从 SavedStateHandle 中检索路由,其中 T 是您的路由类:

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

最后,您可以通过传入路线的实例,使用 navigate() 函数导航到可组合项:

navController.navigate(Profile(id = 123))

此方法会将用户导航到导航图中的 composable<Profile> 目的地。任何导航实参(例如 id)都可以通过使用 NavBackStackEntry.toRoute 重建 Profile 并读取其属性来获取。

其他资源