Navigation 3 在 Jetpack Compose 处理导航状态的方式上发生了根本性转变,与 Navigation 2 相比,在架构方面具有显著优势。
了解将 Wear Compose 应用从 Navigation 2 迁移到 Navigation 3 所需的架构变更和步骤。
Navigation 3 的主要优势
- 直接返回堆栈控制:
NavBackStack从根本上来说只是一个可变的NavKey对象列表,表示用户访问过的屏幕历史记录。您可以像控制任何 KotlinMutableList(add、removeLast、clear)一样控制它。您可以直接操纵列表来执行导航操作,例如添加键以向前导航或移除键以向后导航。 - Compose-First 设计:将返回堆栈建模为标准可观测状态。修改导航历史记录的行为与更新任何其他 Compose 状态完全一样,都会自动触发重组以显示当前界面。
- 默认情况下类型安全:完全消除了基于字符串的路由。 导航功能利用可序列化的数据对象和数据类。
- 分离的演示 (Scene Strategies):界面过渡层(
NavDisplay和SwipeDismissableSceneStrategy)与状态跟踪 (NavBackStack) 完全分离,从而更轻松地集成内置的 Wear OS 导航过渡。
迁移步骤
1. 更新依赖项
移除旧的 androidx.wear.compose:compose-navigation 依赖项,并引入新的拆分 Navigation 3 依赖项,同时支持 Kotlin 序列化。
移除:
implementation("androidx.wear.compose:compose-navigation:...")
添加:
implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...") // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin
2. 更新了目的地以实现 NavKey
在 Navigation 2 中,您可能使用字符串或泛型对象进行路由。在 Navigation 3 中,您必须实现 NavKey 标记接口,并使用 @Serializable 注释每个屏幕对象。
为什么需要这样做?为了能够在进程终止后保存和恢复返回堆栈,底层 navigation3-runtime 依赖于 kotlinx-serialization 来序列化状态。
之前(导航 2 - 通用类型安全路线):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
之后(导航 3 - NavKey + Serializable):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. 替换了路由逻辑(从 NavController 到 NavBackStack)
将 NavController 替换为使用 rememberNavBackStack 初始化的 NavBackStack。您还需要专门针对 Wear OS 实例化 SwipeDismissableSceneStrategy。
之前(导航 2):
val navController = rememberSwipeDismissableNavController()
之后(导航 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. 将 NavHost 替换为 NavDisplay 和 entryProvider DSL
NavHost 容器及其内部 composable("route") { ... } 构建器 DSL 已替换为 NavDisplay 和 entryProvider {
entry<Key> { ... } } DSL。
之前(导航 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
之后(导航 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )