[当尝试在较低范围(ViewModel
)中为继承的ViewModelFactory
(无范围创建)添加@FragmentScope
绑定到多重绑定中时,我一直遇到此错误:
java.lang.IllegalArgumentException:未知模型类com.example.app.MyFragmentVM
((注:下面绝不是详尽的清单,而是两个很好的示例资源和我所研究的建议)]
我刚开始与Dagger合作,所以我不得不做很多Google搜寻来尝试了解正在发生的事情,但是据我所知,我已经达到了应该起作用的地方(?) ...
从类似于[1]的源中,我删除了@Singleton
上的ViewModelFactory
范围,但仍然遇到上述崩溃,即在映射中找不到模型类。
[类似于[2]的资料,我试图加强对依存关系如何工作以及项目如何暴露于依存组件的理解。我知道并了解ViewModelProvider.Factory
及其相关模块如何使用MyFragmentComponent
。
但是我不明白为什么@Binds @IntoMap
对MyFragmentVM
不起作用。
首先让我完成应用程序中已经存在的内容的设置-几乎所有内容都不适用于特定情况
// AppComponent
@Component(modules=[AppModule::class, ViewModelModule::class])
interface AppComponent {
fun viewModelFactory(): ViewModelProvider.Factory
fun inject(activity: MainActivity)
// ... and other injections
}
// AppModule
@Module
class AppModule {
@Provides
@Singleton
fun providesSomething(): Something
// a bunch of other providers for the various injection sites, all @Singleton scoped
}
// ViewModelModule
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindsViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(MainActivityVM::class)
abstract fun bindsMainActivityVM(vm: MainActivityVM): ViewModel
}
// VMFactory
class ViewModelFactory @Injects constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
以下是我尝试添加和利用我的@FragmentScope的方法:
// MyFragmentComponent
@FragmentScope
@Component(
dependencies = [AppComponent::class],
modules = [MyFragmentModule::class, MyFragmentVMModule::class]
)
interface MyFragmentComponent {
fun inject(fragment: MyFragment)
}
// MyFragmentModule
@Module
class MyFragmentModule {
@Provides
@FragmentScope
fun providesVMDependency(): VMDependency {
// ...
}
}
// MyFragmentVMModule
@Module
abstract class MyFragmentVMModule {
@Binds
@IntoMap
@ViewModelKey(MyFragmentVM::class)
abstract fun bindsMyFragmentVM(vm: MyFragmentVM): ViewModel
}
// MyFragment
class MyFragment : Fragment() {
@set:Inject
internal lateinit var vmFactory: ViewModelProvider.Factory
private lateinit var viewModel: MyFragmentVM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DaggerMyFragmentComponent.builder()
.appComponent(MyApplication.instance.component)
.build()
.inject(this)
viewModel = ViewModelProvider(this, vmFactory).get(MyFragmentVM::class.java)
}
}
[这里需要注意的有趣的是,MyFragmentModule
本身并没有最终为MyFragment
提供任何唯一的注入(所有注入均来自AppComponent,因为它现在是这样)。但是,它确实为ViewModel
使用的MyFragment
提供了唯一的注入。
subcomponents和component依赖项>>之间的区别。子组件
ViewModelProvider.Factory
,则注入的映射将包括来自子组件的绑定。 (@Reusable
绑定也是如此,但@Singleton
却不是。)如果将具有依赖关系的组件更改为子组件,那么一切都会正常进行。但是,这可能不适合您所需的体系结构。特别是,如果MyFragmentComponent
在Instant App模块中,则这是不可能的。
组件依赖项
它不知道可能依赖于它的任何组件。这次,当要求提供ViewModelProvider.Factory
时,主要组件除具有自身的访问权限之外,无权访问任何@ViewModelKey
绑定,因此它返回的Factory
将不包括MyFragmentVM
绑定。如果MyFragmentComponent
不需要ViewModel
的任何AppComponent
绑定,则可以将bindsViewModelFactory
提取到其自己的模块中并将其包含在两个组件中。这样,两个组件都可以独立创建自己的Factory
。
如果确实需要ViewModel
中的某些AppComponent
绑定,希望您也可以将这些绑定模块添加到MyFragmentComponent
中。如果不是,则必须在AppComponent
中公开地图,然后以某种方式将这些条目与新绑定结合在一起。 Dagger没有提供执行此操作的好方法。