Android Hilt+Compose Navigation:Activity与Composable间ViewModel实例不一致问题
核心原因
默认情况下,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
相关产品推荐
相关产品推荐

