Dagger2 缺少绑定无法提供 ViewModel 密钥
Dagger2 Missing Binding Cannot Provides ViewModel Key
我正在尝试使用具有多重绑定的 Dagger2 创建我的 ViewModel 的依赖注入,但我收到此错误并且我无法使其工作,我尝试了几个答案(如下)但是 none他们中的一些人帮助了我。
这是我收到的错误:
SaveMyHeroApplicationComponent.java:8: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
这是我的代码
class SaveMyHeroApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerSaveMyHeroApplicationComponent.factory().create(this)
}
}
@Singleton
@Component(modules = [AndroidInjectionModule::class, MainActivityModule::class])
interface SaveMyHeroApplicationComponent : AndroidInjector<SaveMyHeroApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): SaveMyHeroApplicationComponent
}
}
@Module(includes = [NetworkModule::class, HomeModule::class])
class MainActivityModule {
@Provides
fun provideViewModelFactoryProviders(
providers: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
): ViewModelProvider.Factory = SaveMyHeroViewModelFactory(providers)
}
class SaveMyHeroViewModelFactory(
private val providers: Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T =
requireNotNull(getProvider(modelClass).get()) {
"Provider for $modelClass returned null"
}
private fun <T : ViewModel> getProvider(modelClass: Class<T>): Provider<T> =
try {
requireNotNull(providers[modelClass] as Provider<T>) {
"No ViewModel provider is bound for class $modelClass"
}
} catch (error: ClassCastException) {
error("Wrong provider type registered for ViewModel type $error")
}
}
@Module(includes = [HomeModule.ProvideViewModel::class])
abstract class HomeModule {
@ContributesAndroidInjector(modules = [InjectViewModel::class])
abstract fun bind(): HomeFragment
@Module
class ProvideViewModel {
@Provides
@IntoMap
@ViewModelKey(HomeViewModel::class)
fun provideHomeViewModel() = HomeViewModel()
}
@Module
class InjectViewModel {
@Provides
fun provideHomeViewModel(
factory: ViewModelProvider.Factory,
target: HomeFragment
) = ViewModelProvider(target, factory).get(HomeViewModel::class.java)
}
}
@MustBeDocumented
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
此外,这些是我的应用依赖版本:
kotlin_version = ‘1.3.72'
dagger_version = ‘2.27’
gradle:3.6.3
我知道这个问题有几个问题,但我尝试了几个,none 其中对我有用。
这是我尝试阅读和检查的解决方案链接:
https://github.com/android/architecture-components-samples/tree/master/GithubBrowserSample
https://github.com/google/dagger/issues/1478
https://github.com/google/dagger/issues/1478
https://medium.com/chili-labs/android-viewmodel-injection-with-dagger-f0061d3402ff
尝试以Architecture Blueprints sample (dagger-android branch)为例。
Dagger Android 本身就是一团糟,重要的是要遵循一些模板不要走错路。可能您的方法也可以修复,但我建议您尝试更改架构:
- 您的自定义视图模型工厂应该在构造函数中包含@Inject:
class SaveMyHeroViewModelFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
.......
- 您应该添加辅助模块 ViewModelBuilderModule,它提供 ViewModelProvider.Factory(您在所有活动和片段中注入)和您的自定义 ViewModel.Factory:
@Module
abstract class ViewModelBuilderModule {
@Binds
abstract fun bindViewModelFactory(factory: SaveMyHeroViewModelFactory): ViewModelProvider.Factory
}
- 对于你的所有对 - Activitiy/ViewModel 和 Fragment/ViewModel 你应该像这样添加模块(但你可以为所有的人制作一个模块,这取决于你):
@Module
abstract class HomeModule {
@ContributesAndroidInjector(modules = [ViewModelBuilderModule::class])
internal abstract fun bind(): HomeFragment
@Binds
@IntoMap
@ViewModelKey(HomeViewModel::class)
internal abstract fun provideHomeViewModel(viewModel: HomeViewModel): ViewModel
}
- 在您的 Dagger 组件中,您应该使用第 3 步中的所有模块:
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, HomeModule::class, ...])
interface SaveMyHeroApplicationComponent : AndroidInjector<SaveMyHeroApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): SaveMyHeroApplicationComponent
}
}
我正在尝试使用具有多重绑定的 Dagger2 创建我的 ViewModel 的依赖注入,但我收到此错误并且我无法使其工作,我尝试了几个答案(如下)但是 none他们中的一些人帮助了我。
这是我收到的错误:
SaveMyHeroApplicationComponent.java:8: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
这是我的代码
class SaveMyHeroApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerSaveMyHeroApplicationComponent.factory().create(this)
}
}
@Singleton
@Component(modules = [AndroidInjectionModule::class, MainActivityModule::class])
interface SaveMyHeroApplicationComponent : AndroidInjector<SaveMyHeroApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): SaveMyHeroApplicationComponent
}
}
@Module(includes = [NetworkModule::class, HomeModule::class])
class MainActivityModule {
@Provides
fun provideViewModelFactoryProviders(
providers: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
): ViewModelProvider.Factory = SaveMyHeroViewModelFactory(providers)
}
class SaveMyHeroViewModelFactory(
private val providers: Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T =
requireNotNull(getProvider(modelClass).get()) {
"Provider for $modelClass returned null"
}
private fun <T : ViewModel> getProvider(modelClass: Class<T>): Provider<T> =
try {
requireNotNull(providers[modelClass] as Provider<T>) {
"No ViewModel provider is bound for class $modelClass"
}
} catch (error: ClassCastException) {
error("Wrong provider type registered for ViewModel type $error")
}
}
@Module(includes = [HomeModule.ProvideViewModel::class])
abstract class HomeModule {
@ContributesAndroidInjector(modules = [InjectViewModel::class])
abstract fun bind(): HomeFragment
@Module
class ProvideViewModel {
@Provides
@IntoMap
@ViewModelKey(HomeViewModel::class)
fun provideHomeViewModel() = HomeViewModel()
}
@Module
class InjectViewModel {
@Provides
fun provideHomeViewModel(
factory: ViewModelProvider.Factory,
target: HomeFragment
) = ViewModelProvider(target, factory).get(HomeViewModel::class.java)
}
}
@MustBeDocumented
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
此外,这些是我的应用依赖版本:
kotlin_version = ‘1.3.72'
dagger_version = ‘2.27’
gradle:3.6.3
我知道这个问题有几个问题,但我尝试了几个,none 其中对我有用。
这是我尝试阅读和检查的解决方案链接:
https://github.com/android/architecture-components-samples/tree/master/GithubBrowserSample
https://github.com/google/dagger/issues/1478
https://github.com/google/dagger/issues/1478
https://medium.com/chili-labs/android-viewmodel-injection-with-dagger-f0061d3402ff
尝试以Architecture Blueprints sample (dagger-android branch)为例。
Dagger Android 本身就是一团糟,重要的是要遵循一些模板不要走错路。可能您的方法也可以修复,但我建议您尝试更改架构:
- 您的自定义视图模型工厂应该在构造函数中包含@Inject:
class SaveMyHeroViewModelFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
.......
- 您应该添加辅助模块 ViewModelBuilderModule,它提供 ViewModelProvider.Factory(您在所有活动和片段中注入)和您的自定义 ViewModel.Factory:
@Module
abstract class ViewModelBuilderModule {
@Binds
abstract fun bindViewModelFactory(factory: SaveMyHeroViewModelFactory): ViewModelProvider.Factory
}
- 对于你的所有对 - Activitiy/ViewModel 和 Fragment/ViewModel 你应该像这样添加模块(但你可以为所有的人制作一个模块,这取决于你):
@Module
abstract class HomeModule {
@ContributesAndroidInjector(modules = [ViewModelBuilderModule::class])
internal abstract fun bind(): HomeFragment
@Binds
@IntoMap
@ViewModelKey(HomeViewModel::class)
internal abstract fun provideHomeViewModel(viewModel: HomeViewModel): ViewModel
}
- 在您的 Dagger 组件中,您应该使用第 3 步中的所有模块:
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, HomeModule::class, ...])
interface SaveMyHeroApplicationComponent : AndroidInjector<SaveMyHeroApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): SaveMyHeroApplicationComponent
}
}