Navigation 组件出来好几年了,但很多项目还是手写 Fragment 管理。不是它不好用,而是多栈、跨模块、深层链接这些场景容易踩坑。
一、Navigation 解决了什么问题
Fragment 跳转代码散落在 Activity 里
返回栈管理容易出 Bug
深层链接和参数传递写起来乱
多 Tab 各自返回栈难维护
二、基本用法
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") { HomeScreen() }
composable("detail/{itemId}") { backStackEntry ->
val itemId = backStackEntry.arguments?.getString("itemId")
DetailScreen(itemId)
}
}
传参:
navController.navigate("detail/123")
三、深层链接 Deep Link
composable(
route = "detail/{itemId}",
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://detail/{itemId}" }
)
) { ... }
Manifest 里注册:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="detail" />
</intent-filter>
深层链接适合做推送跳转、分享回流、H5 唤起。
四、多栈与 BottomNavigation
@Composable
fun MainScreen() {
val navController = rememberNavController()
Scaffold(
bottomBar = { BottomBar(navController) }
) { padding ->
NavHost(navController, startDestination = "home", Modifier.padding(padding)) {
// 每个 tab 用一个独立的 navigation graph
navigation(startDestination = "home/list", route = "home") { ... }
navigation(startDestination = "profile/main", route = "profile") { ... }
}
}
}
关键点:
每个 Tab 独立 graph
BottomNavigation切 Tab 时保存各自返回栈用
saveState和restoreState实现状态保持
五、跨模块导航
模块化后,不同 feature 的页面互相不能直接引用。常见方案:
字符串路由:
navController.navigate("detail/123")类型安全路由:Navigation 2.8+ 支持 Kotlin Serialization
接口抽象:定义 Navigator 接口,app 模块实现并注入
类型安全示例:
@Serializable
object Detail
composable<Detail> { ... }
navController.navigate(Detail)
小结
Navigation 统一了跳转、返回栈和深层链接
多 Tab 用独立 graph 管理返回栈
深层链接要结合 scheme 注册
跨模块导航推荐类型安全路由或接口抽象
下一篇,我们聊聊包体积优化:Dex、资源、Assets 与混淆实战。
参考阅读
引用链接
[1]Navigation 官方文档: https://developer.android.com/guide/navigation
[2]Type-safe navigation with Kotlin Serialization: https://developer.android.com/guide/navigation/design/type-safety