web-dev-qa-db-ja.com

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

}

しかし、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<KClass<out ViewModel>, Provider<ViewModel>>を提供できるはずですが、なぜクラッシュするのか理解できません。


また、ViewModelKeyの代わりにコンストラクターパラメーターとしてClassを使用して、KClassアノテーションクラスをJavaに切り替えてみました。次に、ViewModelFactoryMap<Class<out ViewModel>, Provider<ViewModel>>に依存するように変更しましたが、同じエラーが発生しました。

20
Bryan

アノテーションで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コンパイラでサポートされていない理由は実際にはわかりません。ここでも同様の問題が発生します: 短剣2:Map <Class <?extends Foo>、Provider <?extends Foo >>

38
Kirill Rakhman