2017-06-19 34 views
17

我想通過自己的KClass類型的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 

} 

但我正在逐漸匕首編譯器錯誤:

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<KClass<out ViewModel>, Provider<ViewModel>>,但我無法弄清楚它爲什麼會崩潰。


我也嘗試過到Java切換ViewModelKey註解類,採取Class作爲構造函數的參數,而不是KClass。然後修改我的ViewModelFactory以取決於Map<Class<out ViewModel>, Provider<ViewModel>>,但發生了相同的錯誤。

回答

30

在註釋中使用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>>

+1

你太棒了,非常感謝 – Roman

+0

令人驚歎。我從來沒有想到過,所有Google Android Architecture項目都是用Java編寫的! – Arjun