android - 如何使用 Dagger Hilt 在动态功能模块中创建 ViewModel?
问题描述
尝试在动态功能模块中创建 ViewModel private val viewModel: PostDetailViewModel by viewModels()
在片段中
class PostDetailFragment : DynamicNavigationFragment<FragmentPostDetailBinding>() {
private val viewModel: PostDetailViewModel by viewModels()
override fun getLayoutRes(): Int = R.layout.fragment_post_detail
override fun bindViews() {
// Get Post from navigation component arguments
val post = arguments?.get("post") as Post
dataBinding.item = post
viewModel.updatePostStatus(post)
}
override fun onCreate(savedInstanceState: Bundle?) {
initCoreDependentInjection()
super.onCreate(savedInstanceState)
}
private fun initCoreDependentInjection() {
val coreModuleDependencies = EntryPointAccessors.fromApplication(
requireActivity().applicationContext,
DomainModuleDependencies::class.java
)
DaggerPostDetailComponent.factory().create(
coreModuleDependencies,
requireActivity().application
)
.inject(this)
}
}
结果错误
Caused by: java.lang.InstantiationException: java.lang.Class<com.x.post_detail.PostDetailViewModel> has no zero argument constructor
它适用于应用程序模块中的任何片段,但不适用于动态功能模块。将 ViewModel 添加到动态功能模块的正确方法是什么?我应该使用 ViewModelFactory 在 app 模块中创建 ViewModel 并从 app 模块中获取它们吗?
解决方案
基于这个官方github帖子
现在在https://developer.android.com/training/dependency-injection/hilt-multi-module#dfm有关于 Hilt 和 DFM 的文档
但总的来说,由于我们是由子组件和整体组件构建的,因此您将无法将标准 Hilt 机制(如 @AndroidEntryPoint 与 DFM)一起使用。
抱歉不行。@ViewModelInject 使用整体的 Hilt ActivityRetainedComponent,因此您的 DFM 中的任何 @ViewModelInject 类都不会被识别。
目前看来,仅使用动态功能模块@ViewModelInject
和by viewModels()
在动态功能模块中注入 ViewModel 似乎是不可能的。
基于格子应用程序,我在动态功能模块中重建了我的 Dagger 模块
@InstallIn(FragmentComponent::class)
@Module
class PostDetailModule {
@Provides
fun providePostDetailViewModel(fragment: Fragment, factory: PostDetailViewModelFactory) =
ViewModelProvider(fragment, factory).get(PostDetailViewModel::class.java)
@Provides
fun provideCoroutineScope() = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())
}
而 ViewModel 和 ViewModelFactory 是
class PostDetailViewModel @ViewModelInject constructor(
private val coroutineScope: CoroutineScope,
private val getPostsUseCase: UseCase
) : ViewModel() {
// Do other things
}
class PostDetailViewModelFactory @Inject constructor(
private val coroutineScope: CoroutineScope,
private val getPostsUseCase: UseCase
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass != PostDetailViewModel::class.java) {
throw IllegalArgumentException("Unknown ViewModel class")
}
return PostDetailViewModel(
coroutineScope,
getPostsUseCase
) as T
}
}
并注入到动态特征模块中的片段
class PostDetailFragment : Fragment() {
@Inject
lateinit var viewModel: PostDetailViewModel
override fun onCreate(savedInstanceState: Bundle?) {
initCoreDependentInjection()
super.onCreate(savedInstanceState)
}
private fun initCoreDependentInjection() {
val coreModuleDependencies = EntryPointAccessors.fromApplication(
requireActivity().applicationContext,
DomainModuleDependencies::class.java
)
DaggerPostDetailComponent.factory().create(
dependentModule = coreModuleDependencies,
fragment = this
)
.inject(this)
}
}
推荐阅读
- php - 动态列/属性。卡住。需要灵感
- r - 在R中反转正则表达式
- ios - React Native - npx react-native run-ios 在初始化项目后不起作用
- php - 相互使用两个特征的正确方法是什么
- c - 为什么 4/14 在 C 中是 0.00000
- azure - 如何使用保存在 Azure Blob 中的遥测数据来构建报告?
- javascript - 带有 Electron-Vue.js 的串口
- python - df.groupby('MONTH')['TASKTYPE'].value_counts().unstack().loc[month_order].plot.bar(stacked=True) - KeyError
- svelte - 如何在 Svelte 中使用系统信息?
- c# - .net Channels:为什么消费者/读者在无界通道中一个接一个地连续消费生产者输出