Android 导航组件与深层链接设计
Android 导航组件与深层链接设计
页面跳转不只是调用一个方法。返回栈结构、参数类型、深链解析和页面状态恢复共同构成导航体系。导航设计混乱时,用户会遇到返回异常、页面重复、参数丢失和通知跳转失败等问题。
一、导航图是页面关系的一等公民
导航图应显式声明页面、参数和跳转关系,而不是把目标类名散落在各个按钮中。
findNavController().navigate(
ProductListFragmentDirections.actionProductListToProductDetail(productId)
)
类型安全的跳转参数能让编译阶段发现拼写和类型错误,比手写 Bundle 字符串更可靠。
二、参数必须声明类型
导航参数应明确类型和默认值,避免所有参数都以字符串传递后在每个页面重复解析。
<argument
android:name="productId"
app:argType="string" />
业务上必须存在的参数应设为不可空,可选参数提供合理默认值。页面内部读取参数时直接得到确定类型。
三、深链只处理合法地址
深链入口可能来自外部浏览器、通知或扫码,参数完全不可信。进入页面前必须校验。
fun parseProductId(raw: String?): String? {
if (raw.isNullOrBlank()) return null
return productRepository.isValidProductId(raw)
}
对于不合法或已失效的目标,应进入兜底页面或首页,不要带着异常参数继续初始化页面。
四、显式深链与隐式深链
显式深链指定目标组件,通常来自应用内通知;隐式深链由系统根据 URI 匹配。两者的返回栈要求不同。
val deepLinkIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.app_graph)
.setDestination(R.id.productDetailFragment)
.setArguments(bundleOf("productId" to productId))
.createTaskStackBuilder()
从通知进入详情页时,用户按返回键通常应回到应用首页,而不是直接退出应用。返回栈结构要与产品行为一致。
五、返回栈不应无限叠加
连续打开详情页、再从推荐进入另一个详情页时,如果每次都压栈,返回会变得漫长。
findNavController().navigate(
direction,
navOptions {
popUpTo(R.id.productListFragment) {
inclusive = false
}
}
)
同类页面切换时应清理中间栈,保留合理的返回路径。支付、登录等一次性页面完成后也应及时出栈。
六、页面状态与导航重建
进程被回收后恢复页面时,导航参数必须能重建目标页面。如果参数来自内存对象,恢复时会丢失。
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(KEY_PRODUCT_ID, productId)
}
跨页面传递的数据应尽量使用可序列化的业务标识,复杂对象通过数据仓库按标识重新获取。
七、底部导航与返回栈
底部导航的每个主页面通常应有独立返回栈,但返回键不应在主页面之间来回切换。
val navOptions = navOptions {
launchSingleTop = true
restoreState = true
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
}
是否保留每个页签的滚动位置和筛选条件,应遵循产品定义。导航框架只提供能力,状态策略仍需明确。
八、动画与转场
页面切换动画应保持轻量,避免每次跳转都执行复杂共享元素动画导致卡顿。
navController.currentDestination
动画参数应集中定义,统一维护进入、退出、弹出和弹入行为。不同页面间动画差异要有产品理由。
九、导航事件不要放在 ViewModel 中
ViewModel 不应直接持有导航控制器。它应暴露事件或状态,由视图层执行导航。
viewModel.submitResult.observe(viewLifecycleOwner) { result ->
if (result.isSuccess) {
findNavController().popBackStack()
}
}
单向数据流让 ViewModel 可测试,也让导航时机由拥有生命周期的视图层决定。
十、覆盖导航测试
导航问题常出现在边界场景。测试应覆盖:
- 深链参数缺失或非法。
- 页面重建后的参数恢复。
- 连续跳转后的返回栈结构。
- 通知进入后的返回行为。
- 底部导航切换后的状态保留。
- 一次性页面完成后的出栈。
总结
导航设计的核心是显式声明页面关系和参数类型。深链入口全部视为不可信数据,进入前校验并构建合理返回栈。同类页面避免无限压栈,一次性页面及时清理。导航事件由视图层执行,状态由 ViewModel 描述,并通过测试覆盖重建和深链等边界场景。
- 点赞
- 收藏
- 关注作者
评论(0)