2017-06-19 26 views
17

próbuję powiązać podklasy ViewModel na mapie przez ich KClass typów:Oprawa na mapę z typem KClass

@Module abstract class ViewModelModule { 

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

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

} 

ale otrzymuję błąd Dagger kompilatora:

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) 

Powyższy ViewModelModule jest zawarty w moim AppModule, który jest modułem w moim AppComponent. Więc Dagger powinien być w stanie dostarczyć Map<KClass<out ViewModel>, Provider<ViewModel>> wymagany przez mój ViewModelFactory, ale nie mogę zrozumieć, dlaczego się zawiesza.


Próbowałem również przełączanie klasę ViewModelKey adnotacji nad Java, biorąc Class jako parametr konstruktora zamiast KClass. Następnie zmodyfikowałem mój ViewModelFactory, aby zależało od Map<Class<out ViewModel>, Provider<ViewModel>>, ale wystąpił ten sam błąd.

Odpowiedz

30

Podczas korzystania z KClass w adnotacji, faktycznie jest kompilowany do Javy Class. Ale rzeczywistym problemem jest wieloznacznik w java.util.Map<kotlin.reflect.KClass<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>>, który generuje kompilator Kotlin.

Zakładając, że @ViewModelKey jest zdefiniowany jako

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

musisz określić swoje miejsce wstrzyknięcia jak

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

Korzystanie @JvmSuppressWildcards zapobiega kompilator od generowania symboli wieloznacznych.

Nie wiem, dlaczego symbole wieloznaczne nie są obsługiwane przez kompilator Dagger. Możesz zobaczyć podobny problem tutaj: Dagger 2: How to inject Map<Class<? extends Foo>, Provider<? extends Foo>>

+1

Jesteś wspaniały, wielkie dzięki – Roman

+0

Amazing. Nigdy bym tego nie zrobił, wszystkie projekty Google Android Architecture są w Javie! – Arjun