You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:多页面共享ViewModel并在超出作用域时销毁

原生Jetpack Compose解决方案:基于嵌套导航图管理表单ViewModel生命周期

针对你的场景,不需要Hilt或多Activity,利用Compose Navigation的嵌套导航图作用域就能实现表单ViewModel在返回HomePage时自动销毁的需求,这是2023年版本的原生最佳实践。

实现步骤

1. 定义导航路由与嵌套图

先统一管理所有页面路由,并为表单流程单独定义一个嵌套导航图的根路由:

sealed class Screen(val route: String) {
    object Home : Screen("home")
    object FormPage1 : Screen("form_page_1")
    object FormPage2 : Screen("form_page_2")
    object FormPage3 : Screen("form_page_3")

    // 表单流程嵌套图的根路由
    companion object {
        const val FORM_FLOW_ROOT = "form_flow_root"
    }
}

2. 配置NavHost与嵌套导航图

在MainActivity的NavHost中,将三个表单页面纳入同一个嵌套导航图,并指定该嵌套图的起始页为FormPage1:

NavHost(navController = navController, startDestination = Screen.Home.route) {
    // 首页
    composable(Screen.Home.route) {
        HomePage(
            onCreateFormClick = {
                // 导航到表单嵌套图的起始页
                navController.navigate(Screen.FORM_FLOW_ROOT)
            }
        )
    }

    // 表单流程嵌套导航图
    navigation(
        startDestination = Screen.FormPage1.route,
        route = Screen.FORM_FLOW_ROOT
    ) {
        // 表单第一页
        composable(Screen.FormPage1.route) { backStackEntry ->
            // 绑定到嵌套图的根作用域获取ViewModel
            val formViewModel = viewModel<FormPageViewModel>(
                viewModelStoreOwner = backStackEntry
            )
            FormPage1(
                viewModel = formViewModel,
                onNext = { navController.navigate(Screen.FormPage2.route) }
            )
        }

        // 表单第二页
        composable(Screen.FormPage2.route) { backStackEntry ->
            // 通过parent获取嵌套图的根作用域,共享同一个ViewModel
            val formViewModel = viewModel<FormPageViewModel>(
                viewModelStoreOwner = backStackEntry.parent!!
            )
            FormPage2(
                viewModel = formViewModel,
                onNext = { navController.navigate(Screen.FormPage3.route) },
                onBack = { navController.popBackStack() }
            )
        }

        // 表单第三页
        composable(Screen.FormPage3.route) { backStackEntry ->
            val formViewModel = viewModel<FormPageViewModel>(
                viewModelStoreOwner = backStackEntry.parent!!
            )
            FormPage3(
                viewModel = formViewModel,
                onSubmit = {
                    // 提交后直接返回首页,清空整个表单流程的回退栈
                    navController.popBackStack(Screen.Home.route, inclusive = false)
                },
                onBack = { navController.popBackStack() }
            )
        }
    }
}

3. 核心原理说明

  • ViewModel作用域绑定:嵌套导航图的根BackStackEntry会作为整个表单流程的ViewModelStoreOwner。FormPage1是嵌套图的起始页,其自身的BackStackEntry就是根作用域;FormPage2、FormPage3通过backStackEntry.parent!!获取根作用域,从而实现三个页面共享同一个ViewModel。
  • 自动销毁时机:当从表单页面返回HomePage时(无论是从FormPage1直接返回,还是从FormPage3提交后返回),整个嵌套导航图的所有BackStackEntry都会被弹出。此时根作用域的ViewModelStore被清理,FormPageViewModel会自动销毁,下次进入表单流程时会重新实例化。
  • 流程内数据保留:在表单流程内部跳转(比如FormPage2回到FormPage1)时,嵌套图的根作用域依然存在,ViewModel不会被销毁,符合表单数据共享的需求。

关键注意事项

  • 返回HomePage时,必须使用popBackStack(Screen.Home.route, inclusive = false),确保一次性弹出表单流程的所有页面,而不是仅弹出当前页面。
  • 无需手动调用ViewModel的清除方法,Navigation组件会自动管理ViewModel的生命周期,完全符合原生最佳实践。

内容的提问来源于stack exchange,提问作者William Humphreys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:33:20