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

如何在Compose独立导航图中创建Hilt共享ViewModel?

基于Hilt在嵌套导航图间共享ViewModel的方案

核心思路

既然两个页面同属于ProductGraph这个嵌套导航图,最合理的方案是将ViewModel的作用域绑定到该导航图的BackStackEntry上——这样ViewModel的生命周期与整个导航图绑定(只有当用户完全离开ProductGraph时才会销毁),既符合业务边界,又避免在全局或Activity层级创建实例的冗余问题。

具体实现步骤

  1. 确保ProductGraph的路由是固定唯一的,用于定位对应的导航栈条目
  2. 在导航图内部获取该导航栈的BackStackEntry实例
  3. 通过Hilt的hiltViewModel()方法,传入该BackStackEntry作为ViewModelStoreOwner,实现同导航图内的Composable共享同一ViewModel实例

代码示例

1. 定义共享ViewModel

@HiltViewModel
class SharedProductViewModel @Inject constructor(
    // 注入所需依赖,比如产品仓库等
) : ViewModel() {
    // 用于存储选中的产品,供详情页读取
    val selectedProduct = mutableStateOf<Product?>(null)

    fun selectProduct(product: Product) {
        selectedProduct.value = product
    }
}

2. 修改ProductGraph导航代码

fun NavGraphBuilder.productGraph(
    navController: NavController
) {
    navigation(
        startDestination = ProductRoutes.ProductListScreen.route,
        route = ProductRoutes.ProductGraph.route
    ) {
        // 缓存ProductGraph对应的BackStackEntry,避免重复获取
        val productGraphBackStackEntry = remember {
            navController.getBackStackEntry(ProductRoutes.ProductGraph.route)
        }

        composable(route = ProductRoutes.ProductListScreen.route) {
            val viewModel: SharedProductViewModel = hiltViewModel(productGraphBackStackEntry)
            ProductListScreen(navController = navController, viewModel = viewModel)
        }

        composable(route = ProductRoutes.ProductDetailScreen.route) {
            val viewModel: SharedProductViewModel = hiltViewModel(productGraphBackStackEntry)
            ProductDetailScreen(navController = navController, viewModel = viewModel)
        }
    }
}

3. 页面中使用ViewModel

以ProductListScreen为例,点击产品时存储选中项:

@Composable
fun ProductListScreen(navController: NavController, viewModel: SharedProductViewModel) {
    // 假设这里有产品列表UI
    LazyColumn {
        items(products) { product ->
            ProductItem(product) {
                viewModel.selectProduct(product)
                navController.navigate(ProductRoutes.ProductDetailScreen.route)
            }
        }
    }
}

ProductDetailScreen中读取选中的产品:

@Composable
fun ProductDetailScreen(navController: NavController, viewModel: SharedProductViewModel) {
    viewModel.selectedProduct.value?.let { product ->
        // 展示产品详情UI
        ProductDetailContent(product)
    } ?: run {
        // 处理未选中产品的情况,比如返回列表页
        LaunchedEffect(Unit) {
            navController.popBackStack()
        }
    }
}

注意事项

  • 必须保证ProductRoutes.ProductGraph.route是固定不变的,否则无法正确获取对应的BackStackEntry
  • 必须使用hiltViewModel()而非普通的viewModel(),才能让Hilt正确注入依赖
  • 该方案的ViewModel生命周期与ProductGraph完全绑定,当用户从ProductGraph跳转到其他导航图时,ViewModel会被销毁,符合内存优化原则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:02:46