,
,
, , - 等)
2. 保留所有图片的 src 和 alt 属性
3. 只翻译标签之间的文本内容
4. 所有英文必须翻译成中文,不保留英文原文
5. 输出完整的HTML代码
HTML内容:
我有一个生产级应用,包含四个底部标签页、九个导航图以及四十多个屏幕。支持来自推送通知的深度链接、第三方服务的 OAuth 回调,以及跨多屏幕流程共享的 ViewModel。
Navigation 2 处理了所有这些功能。虽然实现方式有些混乱——使用字符串路由和 withArgs 的变通方法,但它确实能用。
后来我尝试迁移到 Navigation 3。
第一个屏幕花了我 20 分钟。底部导航用了整整三天。至于深度链接?我差点放弃。
Nav3 确实更好——类型安全的路由、完全可见且由你掌控的返回栈,不再有 NavController 这个黑盒。但迁移路径存在一些文档并未提醒你的坑。共享 ViewModel 的工作方式变了,深度链接现在成了你自己的问题,而屏幕间返回结果也没有内置解决方案。
这是我迁移一个生产级应用过程中学到的一切:好的部分、痛苦的部分,以及那些我希望在我开始之前就有人写下来的变通方案。
Nav3 到底改变了什么
如果你一直在使用 Navigation 2,那么你需要转变以下思维:
返回栈的所有权:
Nav2 —— NavController 在黑盒背后管理一切。
Nav3 —— 你拥有一个 SnapshotStateList 返回栈。完全可见,完全由你掌控。
路由定义:
Nav2 —— 字符串路由:"project_detail/{projectId}/{projectName}"
Nav3 —— 数据类:ProjectDetail(projectId = 42L, projectName = "Alpha")
屏幕注册:
Nav2 —— NavHost + composable() DSL
Nav3 —— NavDisplay + entryProvider
参数类型:
Nav2 —— navArgument(type = NavType.LongType)
Nav3 —— 只需在数据类中声明一个 Long 类型的属性
读取参数:
Nav2 —— backStackEntry.arguments?.getLong("projectId")
Nav3 —— key.projectId
导航调用:
Nav2 —— navController.navigate(route) / navController.popBackStack()
Nav3 —— backStack.add(route) / backStack.removeLastOrNull()
仅参数传递这一项改进,就让迁移变得值得。假设某个屏幕需要项目 ID 和名称。Nav2 的路由看起来是这样的:
// Nav2:带参数的字符串路由
"project_detail/{projectId}/{projectName}"
需要两个 navArgument 声明,两次 backStackEntry.arguments?.getXxx() 调用。只要类型写错,就会在运行时崩溃,并给出毫无帮助的错误信息。
Nav3 的等效写法:
// Nav3:只需一个数据类
@Serializable
数据类 ProjectDetail(
val projectId: Long,
val projectName: String
) : NavKey
编译期类型安全。IDE 自动补全。无需解析。
设置 Nav3
依赖项
# gradle/libs.versions.toml
[versions]
nav3 =
免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。
我有一个生产级应用,包含四个底部标签页、九个导航图以及四十多个屏幕。支持来自推送通知的深度链接、第三方服务的 OAuth 回调,以及跨多屏幕流程共享的 ViewModel。
Navigation 2 处理了所有这些功能。虽然实现方式有些混乱——使用字符串路由和 withArgs 的变通方法,但它确实能用。
后来我尝试迁移到 Navigation 3。
第一个屏幕花了我 20 分钟。底部导航用了整整三天。至于深度链接?我差点放弃。
Nav3 确实更好——类型安全的路由、完全可见且由你掌控的返回栈,不再有 NavController 这个黑盒。但迁移路径存在一些文档并未提醒你的坑。共享 ViewModel 的工作方式变了,深度链接现在成了你自己的问题,而屏幕间返回结果也没有内置解决方案。
这是我迁移一个生产级应用过程中学到的一切:好的部分、痛苦的部分,以及那些我希望在我开始之前就有人写下来的变通方案。
Nav3 到底改变了什么
如果你一直在使用 Navigation 2,那么你需要转变以下思维:
返回栈的所有权:
Nav2 —— NavController 在黑盒背后管理一切。
Nav3 —— 你拥有一个 SnapshotStateList 返回栈。完全可见,完全由你掌控。
路由定义:
Nav2 —— 字符串路由:"project_detail/{projectId}/{projectName}"
Nav3 —— 数据类:ProjectDetail(projectId = 42L, projectName = "Alpha")
屏幕注册:
Nav2 —— NavHost + composable() DSL
Nav3 —— NavDisplay + entryProvider
参数类型:
Nav2 —— navArgument(type = NavType.LongType)
Nav3 —— 只需在数据类中声明一个 Long 类型的属性
读取参数:
Nav2 —— backStackEntry.arguments?.getLong("projectId")
Nav3 —— key.projectId
导航调用:
Nav2 —— navController.navigate(route) / navController.popBackStack()
Nav3 —— backStack.add(route) / backStack.removeLastOrNull()
仅参数传递这一项改进,就让迁移变得值得。假设某个屏幕需要项目 ID 和名称。Nav2 的路由看起来是这样的:
// Nav2:带参数的字符串路由
"project_detail/{projectId}/{projectName}"
需要两个 navArgument 声明,两次 backStackEntry.arguments?.getXxx() 调用。只要类型写错,就会在运行时崩溃,并给出毫无帮助的错误信息。
Nav3 的等效写法:
// Nav3:只需一个数据类
@Serializable
数据类 ProjectDetail(
val projectId: Long,
val projectName: String
) : NavKey
编译期类型安全。IDE 自动补全。无需解析。
设置 Nav3
依赖项
# gradle/libs.versions.toml
[versions]
nav3 =
免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。