【问题标题】:Binding Into Map With KClass Type使用 KClass 类型绑定到 Map
【发布时间】:2017-11-22 03:51:26
【问题描述】:

我正在尝试通过 KClass 类型将 ViewModel 的子类绑定到地图中:

@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 应该能够提供我的ViewModelFactory 所需的Map&lt;KClass&lt;out ViewModel&gt;, Provider&lt;ViewModel&gt;&gt;,但我不知道它为什么会崩溃。


我还尝试将ViewModelKey 注释类切换到Java,将Class 作为构造函数参数而不是KClass。然后将我的ViewModelFactory修改为依赖Map&lt;Class&lt;out ViewModel&gt;, Provider&lt;ViewModel&gt;&gt;,但出现了同样的错误。

【问题讨论】:

    标签: android dependency-injection kotlin dagger-2 dagger


    【解决方案1】:

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

    假设@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>>

    【讨论】:

    • 太棒了。我永远不会做到这一点,所有 Google Android 架构项目都是用 Java 编写的!
    • 如果可以的话,我会投票 10 次。非常感谢。
    • 这是否意味着您不能将KClass&lt;T&gt; 注入Kotlin 代码,而只能注入Class&lt;T&gt;
    • @andras 你可以,但是这里都没有注入。
    • @KirillRakhman 你说When using KClass in an annotation, it actually gets compiled to Java's Class。我认为这是真的,因为我做了几个测试。当我尝试注入 KClass 时,Dagger2 总是抛出错误,与注解的值是 KClass(如在您的 ViewModelKey 示例中)还是只是 Class 无关。在每个链接的示例中,总会注入一个Class。我希望我能在 Dagger2 中看到实际的依赖关系图以进行调试,但没有办法做到这一点,即使使用kapt 而不是annotationProcessor 也是如此。 (TLDR:但是怎么做?)
    猜你喜欢
    • 2015-08-11
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    相关资源
    最近更新 更多