使用KClass类型绑定到映射

问题描述 投票:20回答:1

我试图通过他们的ViewModel类型将KClass的子类绑定到地图中:

@Module abstract class ViewModelModule {

    @Binds @IntoMap @ViewModelKey(MyViewModel::class)
    abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel

    @Binds abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

}

但我得到Dagger编译错误:

e: ~/Example/app/build/tmp/kapt3/stubs/debug/com/example/app/injection/AppComponent.java:5: error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
e: 

e: public abstract interface AppComponent {
e:                 ^
e:       java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
e:           com.example.app.ui.ViewModelFactory.<init>(creators)
e:       com.example.app.ui.ViewModelFactory is injected at
e:           com.example.app.injection.ViewModelModule.bindViewModelFactory(p0)
e:       android.arch.lifecycle.ViewModelProvider.Factory is injected at
e:           com.example.app.ui.MyFragment.setViewModelFactory(p0)
e:       com.example.app.ui.MyFragment is injected at
e:           dagger.android.AndroidInjector.inject(arg0)

上面的ViewModelModule包含在我的AppModule中,这是我AppComponent中的一个模块。所以Dagger应该能够提供我的Map<KClass<out ViewModel>, Provider<ViewModel>>所需的ViewModelFactory,但我无法弄清楚它为什么会崩溃。


我也尝试将ViewModelKey注释类转换为Java,将Class作为构造函数参数而不是KClass。然后修改我的ViewModelFactory依赖于Map<Class<out ViewModel>, Provider<ViewModel>>,但发生了同样的错误。

android dependency-injection kotlin dagger-2 dagger
1个回答
38
投票

在注释中使用KClass时,它实际上被编译为Java的Class。但实际问题是Kotlin编译器正在生成的java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>>中的通配符。

假设@ViewModelKey被定义为

@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

您需要将注射部位定义为

Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>

使用@JvmSuppressWildcards将阻止编译器生成通配符。

我实际上并不知道,为什么Dagger编译器不支持通配符。你可以在这里看到类似的问题:Dagger 2: How to inject Map<Class<? extends Foo>, Provider<? extends Foo>>

© www.soinside.com 2019 - 2024. All rights reserved.