Navigation Compose API 使您可以在 Compose 应用中的可组合项之间导航,同时利用 Jetpack Navigation 的组件、基础架构和功能。
本页介绍如何将基于 Fragment 的 Jetpack Navigation 迁移到 Navigation Compose,这是将基于 View 的 UI 迁移到 Jetpack Compose 的更大迁移的一部分。
迁移前提条件
当您能够将所有 Fragment 替换为相应的屏幕可组合项后,即可迁移到 Navigation Compose。屏幕可组合项可以包含Compose 和 View 内容的混合,但所有导航目的地都必须是可组合项才能启用 Navigation Compose 迁移。在此之前,您应继续在互操作 View 和 Compose 代码库中使用基于 Fragment 的导航组件。如需了解更多信息,请参阅导航互操作性文档。
在仅限 Compose 的应用中使用 Navigation Compose 并非前提条件。只要您保留 Fragment 用于托管可组合内容,您就可以继续使用基于 Fragment 的导航组件。
迁移步骤
无论您是遵循我们的推荐迁移策略还是采取其他方法,您都会达到所有导航目的地都是屏幕可组合项的阶段,Fragment 仅充当可组合容器。在此阶段,您可以迁移到 Navigation Compose。
如果您的应用已遵循UDF 设计模式和我们的架构指南,则迁移到 Jetpack Compose 和 Navigation Compose 不应需要对应用的其他层(UI 层除外)进行重大重构。
要迁移到 Navigation Compose,请按照以下步骤操作
- 将Navigation Compose 依赖项添加到您的应用中。
创建一个
App-level
可组合项,并将其添加到您的Activity
中作为 Compose 入口点,取代 View 布局的设置class SampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample) setContent { SampleApp(/* ... */) } } }
为每个导航目的地创建类型。对于不需要任何数据的目的地,请使用
data object
;对于需要数据的目的地,请使用data class
或class
。@Serializable data object First @Serializable data class Second(val id: String) @Serializable data object Third
在所有需要引用
NavController
的可组合项都可以访问它的位置(通常在您的App
可组合项中)设置该控制器。这种方法遵循状态提升原则,让您可以将NavController
用作在可组合屏幕之间导航和维护返回堆栈的唯一数据源。@Composable fun SampleApp() { val navController = rememberNavController() // ... }
在
App
可组合项中创建应用的NavHost
并传递navController
@Composable fun SampleApp() { val navController = rememberNavController() SampleNavHost(navController = navController) } @Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { // ... } }
添加
composable
目的地以构建您的导航图。如果每个屏幕都已迁移到 Compose,则此步骤仅包括将这些屏幕可组合项从 Fragment 提取到composable
目的地。class FirstFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setContent { // FirstScreen(...) EXTRACT FROM HERE } } } } @Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { composable<First> { FirstScreen(/* ... */) // EXTRACT TO HERE } composable<Second> { SecondScreen(/* ... */) } // ... } }
如果您遵循了关于构建 Compose UI 架构的指南,特别是关于如何将
ViewModel
和导航事件传递给可组合项的指南,那么下一步是更改您向每个屏幕可组合项提供ViewModel
的方式。您通常可以通过hiltViewModel
使用 Hilt 注入及其与 Compose 和 Navigation 的集成点。@Composable fun FirstScreen( // viewModel: FirstViewModel = viewModel(), viewModel: FirstViewModel = hiltViewModel(), onButtonClick: () -> Unit = {}, ) { // ... }
将所有
findNavController()
导航调用替换为navController
调用,并将这些调用作为导航事件传递给每个可组合屏幕,而不是传递整个navController
。这种方法遵循最佳实践,将事件从可组合函数公开给调用方,并保持navController
作为唯一的真相来源。通过创建为该目的地定义的路由类的实例,可以将数据传递到目的地。然后,可以直接从目的地的返回堆栈条目中获取数据,也可以使用
SavedStateHandle.toRoute()
从ViewModel
中获取数据。@Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { composable<First> { FirstScreen( onButtonClick = { // findNavController().navigate(firstScreenToSecondScreenAction) navController.navigate(Second(id = "ABC")) } ) } composable<Second> { backStackEntry -> val secondRoute = backStackEntry.toRoute<Second>() SecondScreen( id = secondRoute.id, onIconClick = { // findNavController().navigate(secondScreenToThirdScreenAction) navController.navigate(Third) } ) } // ... } }
移除所有 Fragment、相关的 XML 布局、不必要的导航及其他资源,以及过时的 Fragment 和 Jetpack Navigation 依赖项。
您可以在设置文档中找到包含更多 Navigation Compose 相关详细信息的相同步骤。
常见用例
无论您使用哪种导航组件,相同的导航原则均适用。
迁移时的常见用例包括:
有关这些用例的更详细信息,请参阅使用 Compose 导航。
导航时检索复杂数据
强烈建议在导航时不要传递复杂的 数据对象。相反,在执行导航操作时,应以参数形式传递最少必要的信息,例如唯一标识符或其他形式的 ID。您应该将复杂对象作为数据存储在单一真相来源中,例如数据层。如需了解更多信息,请参阅导航时检索复杂数据。
如果您的 Fragment 以参数形式传递复杂对象,请考虑首先重构您的代码,使其能够从数据层存储和获取这些对象。有关示例,请参阅Now in Android 仓库。
限制
本节介绍 Navigation Compose 的当前限制。
增量迁移到 Navigation Compose
目前,在代码中仍使用 Fragment 作为目的地时,无法使用 Navigation Compose。要开始使用 Navigation Compose,所有目的地都必须是可组合项。您可以在问题跟踪器上跟踪此功能请求。
过渡动画
从Navigation 2.7.0-alpha01开始,之前由AnimatedNavHost
提供的自定义过渡设置功能现已直接在NavHost
中支持。如需了解更多信息,请阅读版本说明。
了解详情
有关迁移到 Navigation Compose 的更多信息,请参阅以下资源:
- Navigation Compose Codelab:通过动手实践 Codelab 学习 Navigation Compose 的基础知识。
- Now in Android 仓库:一个完全用 Kotlin 和 Jetpack Compose 构建的功能齐全的 Android 应用,它遵循 Android 设计和开发最佳实践,并包含 Navigation Compose。
- 将 Sunflower 迁移到 Jetpack Compose:一篇博客文章,记录了 Sunflower 示例应用从 Views 迁移到 Compose 的历程,其中也包括迁移到 Navigation Compose。
- 适用于所有屏幕的 Jetnews:一篇博客文章,记录了 Jetnews 示例的重构和迁移,以通过 Jetpack Compose 和 Navigation Compose 支持所有屏幕。
推荐给您
- 注意:当 JavaScript 关闭时,会显示链接文本
- 使用 Compose 导航
- Compose 和其他库
- 其他注意事项