自定义ViewModelStoreOwner创建HiltViewModel崩溃的排查与解决
我有一段可正常运行的Compose代码:
val pagerVM = hiltViewModel( creationCallback = { factory: JourneySummaryPagerViewModel.Factory -> factory.create(selectedIndex.value) }, key = viewModel.journeys.toString() ) JourneySummaryPager( viewModel = pagerVM )
出于项目需求,我需要将ViewModel的生成限定在特定的ViewModelStoreOwner范围内,因此编写了如下代码:
val storeOwner = object : ViewModelStoreOwner { override val viewModelStore = ViewModelStore() } CompositionLocalProvider(value = LocalViewModelStoreOwner provides storeOwner) { val pagerVM = hiltViewModel( creationCallback = { factory: JourneySummaryPagerViewModel.Factory -> factory.create(selectedIndex.value) }, key = viewModel.journeys.toString() ) JourneySummaryPager( viewModel = pagerVM ) }
但启动应用时出现崩溃,报错信息如下:
java.lang.RuntimeException: Cannot create an instance of class
fr.tisseo.android.screen.map.header.journey.journeySummaryPager.JourneySummaryPagerViewModel
at
androidx.lifecycle.viewmodel.internal.JvmViewModelProviders.createViewModel(JvmViewModelProviders.kt:40)
请问如何让Hilt能够通过自定义ViewModelStoreOwner创建我的ViewModel?
崩溃的核心原因是自定义的ViewModelStoreOwner没有关联Hilt的依赖注入上下文,Hilt无法在这个自定义实例中获取ViewModel所需的依赖与Factory。解决步骤如下:
定义Hilt EntryPoint获取ViewModelFactory
先创建一个EntryPoint接口,用于从Hilt组件中获取ViewModelFactory:@InstallIn(SingletonComponent::class) // 根据你的实际依赖范围调整,比如ActivityComponent/FragmentComponent @EntryPoint interface ViewModelFactoryEntryPoint { fun viewModelFactory(): ViewModelProvider.Factory }实现带Hilt支持的自定义ViewModelStoreOwner
让自定义的ViewModelStoreOwner同时实现HasDefaultViewModelProviderFactory接口,绑定Hilt提供的ViewModelFactory:// 从当前应用上下文获取Hilt EntryPoint val entryPoint = EntryPointAccessors.fromApplication( LocalContext.current.applicationContext, ViewModelFactoryEntryPoint::class.java ) val hiltViewModelFactory = entryPoint.viewModelFactory() val storeOwner = object : ViewModelStoreOwner, HasDefaultViewModelProviderFactory { override val viewModelStore = ViewModelStore() override val defaultViewModelProviderFactory: ViewModelProvider.Factory get() = hiltViewModelFactory }保持原有调用逻辑即可
现在在CompositionLocalProvider内部调用hiltViewModel时,就能通过自定义storeOwner的Hilt Factory正确创建ViewModel:CompositionLocalProvider(value = LocalViewModelStoreOwner provides storeOwner) { val pagerVM = hiltViewModel( creationCallback = { factory: JourneySummaryPagerViewModel.Factory -> factory.create(selectedIndex.value) }, key = viewModel.journeys.toString() ) JourneySummaryPager(viewModel = pagerVM) }
额外注意事项
- 确保
JourneySummaryPagerViewModel及其Factory是由Hilt管理的(比如使用@HiltViewModel注解,Factory由Hilt自动生成) - 自定义的ViewModelStoreOwner需要在合适的时机调用
viewModelStore.clear(),避免内存泄漏
内容的提问来源于stack exchange,提问作者Kevin ABRIOUX

