Navigation
应用导航 · androidx.navigation
Navigation 2:NavController 与 Graph2.10.0-beta01
使用类型安全 route、NavHost、NavOptions 和 NavBackStackEntry 建立 Compose 导航。
最后更新 2026-08-01
类型化 route
@Serializable object Home
@Serializable data class Profile(val userId: String)
val navController = rememberNavController()
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(onProfile = { id ->
navController.navigate(Profile(id))
})
}
composable<Profile> { entry ->
val route = entry.toRoute<Profile>()
ProfileScreen(route.userId)
}
}route 参数原则:只携带定位目标所需的小型参数(ID、枚举)。完整对象由目标页通过 repository 读取——避免参数变旧、过大或难以恢复。
NavOptions:控制导航行为
navController.navigate(
route = Profile(userId),
navOptions = NavOptions.Builder()
.setLaunchSingleTop(true) // 顶部已有该路由则复用
.setPopUpTo(Home, inclusive = false) // 弹出到 Home(保留 Home)
.setRestoreState(true) // 恢复目标状态
.build(),
)| 选项 | 作用 |
|---|---|
launchSingleTop | 目标已在栈顶则不重复入栈 |
popUpTo(route) | 弹出到指定路由(inclusive 决定是否连它也弹) |
popUpToSaveState / restoreState | 保存/恢复被弹出的状态 |
enterAnim/exitAnim | 转场动画 |
NavBackStackEntry:读取参数与状态
composable<Profile> { entry ->
val userId = entry.toRoute<Profile>().userId
// SavedStateHandle:进程重建恢复
val handle = entry.savedStateHandle
ProfileScreen(userId)
}entry.toRoute<T>()解析类型化参数。entry.savedStateHandle拿该 entry 的 SavedStateHandle(配合 ViewModel)。currentBackStackEntryFlow观察 entry 变化——UI 优先用 Compose 专用扩展。
返回与结果
// 目标页返回结果
navController.previousBackStackEntry
?.savedStateHandle
?.set("result", value)
navController.popBackStack()
// 源页接收
composable<Home> { entry ->
val result = entry.savedStateHandle.getStateFlow("result", null)
...
}常见陷阱
- 重复导航:事件重放 → 同一目标多次 push。导航是一次性 UI 行为,在事件消费边界处理;
launchSingleTop不是重复事件补丁。 - 大对象当参数:不可序列化或 Bundle 超限 → 崩溃;只传 ID。
- 深度链接/恢复状态:需要
restoreState才能恢复到被弹出的页面状态。 - Graph 层级混乱:用嵌套 graph(
navigation<T>)组织结构,避免扁平大图。 - 忘记依赖:
androidx.navigation:navigation-compose+navigation-common(KMP)。
复制即用
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import kotlinx.serialization.Serializable
@Serializable object Home
@Serializable data class Profile(val userId: String)
@Composable
fun AppNav() {
val navController = rememberNavController()
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(onProfile = { id ->
navController.navigate(Profile(id)) {
launchSingleTop = true
}
})
}
composable<Profile> { entry ->
val userId = entry.toRoute<Profile>().userId
ProfileScreen(userId, onBack = { navController.popBackStack() })
}
}
}要点
- 类型化 route + NavHost + composable<T>;参数只带小型定位数据。
- NavOptions 控制 singleTop/popUpTo/状态恢复/动画。
- SavedStateHandle 在 entry 上,配合 ViewModel 做恢复。
- 一次性导航事件在消费边界处理,别用 singleTop 掩盖重复。