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

Android Hilt+Compose Navigation:Activity与Composable间ViewModel实例不一致问题

解决Hilt ViewModel在Compose Navigation中复用Activity实例的问题

核心原因

默认情况下,hiltViewModel()会以当前NavBackStackEntry作为ViewModelStoreOwner,所以每个导航目的地都会生成独立的ViewModel实例。而直接在Activity中调用Composable时,使用的是Activity自身的ViewModelStoreOwner,因此能复用同一个实例。

解决方案:指定ViewModelStoreOwner为Activity

要让NavHost中的Composable复用Activity初始化的ViewModel实例,只需在调用hiltViewModel()时显式指定ViewModelStoreOwner为当前Activity即可,无需手动传递ViewModel。

1. 在目标Composable中获取Activity的ViewModelStoreOwner

在SelectPaymentTypeScreen中,通过LocalContext获取当前Activity并强转为ViewModelStoreOwner,以此作为参数传入hiltViewModel():

@Composable
fun SelectPaymentTypeScreen() {
    val activity = LocalContext.current as AppCompatActivity
    val viewModel: PaymentFlowViewModel = hiltViewModel(activity)
    
    // 此处使用的viewModel即为Activity中初始化的实例,可直接读取已设置的amount值
}

2. 确认基础注解配置正确

确保你的PaymentActivity已标注@AndroidEntryPoint,PaymentFlowViewModel已标注@HiltViewModel(你已完成这两步,无需额外修改):

@AndroidEntryPoint
class PaymentActivity : AppCompatActivity() {
    // Activity中初始化ViewModel的逻辑保持不变
    private val viewModel: PaymentFlowViewModel by viewModels()
}

@HiltViewModel
class PaymentFlowViewModel @Inject constructor() : ViewModel() {
    var amount by mutableStateOf(0.0)
}

3. 保持NavHost原有配置

你的PaymentFlow中的NavHost无需修改,正常配置导航目的地即可:

@Composable
fun PaymentFlow() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "select_payment_type") {
        composable("select_payment_type") {
            SelectPaymentTypeScreen()
        }
        // 其他导航目的地配置
    }
}

补充说明

这种方式会将ViewModel的生命周期与Activity绑定,而非单个导航页面,非常适合支付流程这类需要跨多个页面共享状态的场景。后续其他需要使用该ViewModel的Composable,都可以用同样的方式获取,确保复用同一个实例。

内容的提问来源于stack exchange,提问作者Ciro González

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:20:56