Привязка К Карте С Типом 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. Так что Кинжал должен быть в состоянии обеспечить Map<KClass<out ViewModel>, Provider<ViewModel>>, требуемое моим ViewModelFactory, но я не могу понять, почему он разбивается.


Я также попытался переключить класс аннотаций ViewModelKey на Java, взяв Class в качестве параметра конструктора вместо KClass. Затем модифицировал мой ViewModelFactory, чтобы зависеть от Map<Class<out ViewModel>, Provider<ViewModel>>, но произошла та же ошибка.

1 19

1 ответ:

При использовании KClass в аннотации он фактически компилируется в Java Class. Но на самом деле проблема заключается в подстановочном знаке в java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>>, который генерирует компилятор Kotlin.

Предполагая, что @ViewModelKey определяется как

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

Вам нужно будет определить место инъекции как

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

Использование @JvmSuppressWildcards не позволит компилятору создавать подстановочные знаки.

Я на самом деле не знаю, почему подстановочные знаки не поддерживаются компилятором Dagger. Вы можете увидеть аналогичную проблему здесь: Кинжал 2: Как ввести Map , провайдер удлиняет Фу>>