Dagger/MissingBinding 将依赖项注入 ViewModel 时
Dagger/MissingBinding when Injecting Dependencies into a ViewModel
我正在尝试将我的存储库注入到我的 ViewModel 中。但是,在编译代码时,我不断收到此错误。我不知道该去哪里...
C:\Users\Anon\AndroidStudioProjects\Barrechat192\app\build\tmp\kapt3\stubs\debug\com\example\barrechat192\di\AppComponent.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.
public abstract interface AppComponent {
^
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.barremap.di.BarreMapComponent
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.camera.di.CameraComponent
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.photoview.di.PhotoViewComponent
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.example.barrechat192.di.FoundationViewModelFactory(creators)
com.example.barrechat192.di.FoundationViewModelFactory is injected at
com.example.barrechat192.di.ViewModelBuilderModule.bindViewModelFactory(factory)
androidx.lifecycle.ViewModelProvider.Factory is injected at
com.example.barrechat192.ui.fragments.photoeditor.PhotoEditorFragment.viewModelFactory
com.example.barrechat192.ui.fragments.photoeditor.PhotoEditorFragment is injected at
正如他们在示例中所做的那样,我使用一个组件设置我的应用程序,然后为每个片段创建子组件。
@Singleton
@Component(
modules = [
AppModule::class,
ViewModelBuilderModule::class,
SubcomponentsModule::class
]
)
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context) : AppComponent
}
fun barreMapComponent(): BarreMapComponent.Factory
fun cameraComponent() : CameraComponent.Factory
fun photoEditorComponent(): PhotoEditorComponent.Factory
fun photoViewComponent(): PhotoViewComponent.Factory
}
@Module(
subcomponents = [
BarreMapComponent::class,
CameraComponent::class,
PhotoEditorComponent::class,
PhotoViewComponent::class
]
)
object SubcomponentsModule
每个子组件都有一个与其注入的 ViewModel 相关的模块。我正在展示四个中的一个。
@Subcomponent(modules = [BarreMapModule::class])
interface BarreMapComponent {
@Subcomponent.Factory
interface Factory{
fun create() : BarreMapComponent
}
fun inject(fragment: BarreMapFragment)
}
@Module
abstract class BarreMapModule {
@Binds
@IntoMap
@ViewModelKey(BarreMapViewModel::class)
abstract fun bindViewModel(viewModel: BarreMapViewModel) : ViewModel
}
最后是处理 ViewModelFactory 注入的模块,
class FoundationViewModelFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("Unknown model class: $modelClass")
}
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
@Module
abstract class ViewModelBuilderModule {
@Binds
abstract fun bindViewModelFactory(
factory: FoundationViewModelFactory
): ViewModelProvider.Factory
}
@Target(
AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
这些被注入到片段中
class BarreMapFragment: Fragment() {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val mapViewModel by viewModels<BarreMapViewModel> { viewModelFactory }
}
您的片段可能不需要子组件。让我为您简化代码...
在您的 AppComponent
class 中,将您的代码替换为:
@Singleton
@Component(modules = [ViewModelModule::class])
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application?): Builder?
fun build(): ApplicationComponent?
}
fun inject(fragment: BarreMapFragment)
// Other fragments or activities are included here
}
创建一个 ViewModelModule
class 以提供您的 ViewModelFactory 和其他 ViewModel classes
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory:
FoundationViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(BarreMapViewModel::class)
abstract fun bindViewModel(viewModel: BarreMapViewModel) : ViewModel
// Provide other ViewModel classes here
}
然后在您的 BarreMapViewModel
class 中,像这样注入您的存储库:
class ChartViewModel @Inject constructor(private val repository: Repository) :
ViewModel() {}
如果有帮助请告诉我。
我正在尝试将我的存储库注入到我的 ViewModel 中。但是,在编译代码时,我不断收到此错误。我不知道该去哪里...
C:\Users\Anon\AndroidStudioProjects\Barrechat192\app\build\tmp\kapt3\stubs\debug\com\example\barrechat192\di\AppComponent.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.
public abstract interface AppComponent {
^
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.barremap.di.BarreMapComponent
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.camera.di.CameraComponent
A binding with matching key exists in component: com.example.barrechat192.ui.fragments.photoview.di.PhotoViewComponent
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.example.barrechat192.di.FoundationViewModelFactory(creators)
com.example.barrechat192.di.FoundationViewModelFactory is injected at
com.example.barrechat192.di.ViewModelBuilderModule.bindViewModelFactory(factory)
androidx.lifecycle.ViewModelProvider.Factory is injected at
com.example.barrechat192.ui.fragments.photoeditor.PhotoEditorFragment.viewModelFactory
com.example.barrechat192.ui.fragments.photoeditor.PhotoEditorFragment is injected at
正如他们在示例中所做的那样,我使用一个组件设置我的应用程序,然后为每个片段创建子组件。
@Singleton
@Component(
modules = [
AppModule::class,
ViewModelBuilderModule::class,
SubcomponentsModule::class
]
)
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context) : AppComponent
}
fun barreMapComponent(): BarreMapComponent.Factory
fun cameraComponent() : CameraComponent.Factory
fun photoEditorComponent(): PhotoEditorComponent.Factory
fun photoViewComponent(): PhotoViewComponent.Factory
}
@Module(
subcomponents = [
BarreMapComponent::class,
CameraComponent::class,
PhotoEditorComponent::class,
PhotoViewComponent::class
]
)
object SubcomponentsModule
每个子组件都有一个与其注入的 ViewModel 相关的模块。我正在展示四个中的一个。
@Subcomponent(modules = [BarreMapModule::class])
interface BarreMapComponent {
@Subcomponent.Factory
interface Factory{
fun create() : BarreMapComponent
}
fun inject(fragment: BarreMapFragment)
}
@Module
abstract class BarreMapModule {
@Binds
@IntoMap
@ViewModelKey(BarreMapViewModel::class)
abstract fun bindViewModel(viewModel: BarreMapViewModel) : ViewModel
}
最后是处理 ViewModelFactory 注入的模块,
class FoundationViewModelFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("Unknown model class: $modelClass")
}
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
@Module
abstract class ViewModelBuilderModule {
@Binds
abstract fun bindViewModelFactory(
factory: FoundationViewModelFactory
): ViewModelProvider.Factory
}
@Target(
AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
这些被注入到片段中
class BarreMapFragment: Fragment() {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val mapViewModel by viewModels<BarreMapViewModel> { viewModelFactory }
}
您的片段可能不需要子组件。让我为您简化代码...
在您的 AppComponent
class 中,将您的代码替换为:
@Singleton
@Component(modules = [ViewModelModule::class])
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application?): Builder?
fun build(): ApplicationComponent?
}
fun inject(fragment: BarreMapFragment)
// Other fragments or activities are included here
}
创建一个 ViewModelModule
class 以提供您的 ViewModelFactory 和其他 ViewModel classes
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory:
FoundationViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(BarreMapViewModel::class)
abstract fun bindViewModel(viewModel: BarreMapViewModel) : ViewModel
// Provide other ViewModel classes here
}
然后在您的 BarreMapViewModel
class 中,像这样注入您的存储库:
class ChartViewModel @Inject constructor(private val repository: Repository) :
ViewModel() {}
如果有帮助请告诉我。