kotlin + Dagger2: не может быть предоставлен без @Предоставляет-аннотированный метод
Я не понимаю, почему я получаю эту ошибку:
Error:(12, 2) error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
public abstract interface ApplicationComponent {
^
java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
com.chintansoni.android.architecturecomponentsblueprint.viewmodel.KotlinViewModelFactory.<init>(creators)
com.chintansoni.android.architecturecomponentsblueprint.viewmodel.KotlinViewModelFactory is injected at
com.chintansoni.android.architecturecomponentsblueprint.view.activity.SplashActivity.viewModelFactory
com.chintansoni.android.architecturecomponentsblueprint.view.activity.SplashActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
KotlinApplication.kt
class KotlinApplication : Application(), HasActivityInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
initializeLogger()
initializeAppInjector()
}
private fun initializeAppInjector() {
AppInjector.init(this)
}
private fun initializeLogger() {
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
}
override fun activityInjector(): DispatchingAndroidInjector<Activity>? {
return dispatchingAndroidInjector
}
}
AppInjector.kt
object AppInjector {
fun init(kotlinApplication: KotlinApplication) {
DaggerApplicationComponent.builder()
.application(kotlinApplication)
.build()
.inject(kotlinApplication)
kotlinApplication.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
handleActivity(activity)
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityDestroyed(activity: Activity) {
}
})
}
private fun handleActivity(activity: Activity) {
if (activity is HasSupportFragmentInjector) {
AndroidInjection.inject(activity)
}
(activity as? FragmentActivity)?.supportFragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(fm: FragmentManager, f: Fragment,
savedInstanceState: Bundle) {
if (f is Injectable) {
AndroidSupportInjection.inject(f)
}
}
}, true)
}
}
ApplicationComponent.kt
@Singleton
@Component(modules = [(AndroidSupportInjectionModule::class), (AppModule::class), (SplashActivityModule::class)])
interface ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): ApplicationComponent
}
fun inject(kotlinApplication: KotlinApplication)
}
AppModule.kt
@Module(includes = [(ViewModelModule::class)])
class AppModule {
@Singleton
@Provides
fun provideApiService(): ApiService {
return Retrofit.Builder()
.baseUrl("https://randomuser.me/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.build()
.create(ApiService::class.java)
}
}
ViewModelModule.kt
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(SplashViewModel::class)
abstract fun bindSplashViewModel(splashViewModel: SplashViewModel): ViewModel
@Binds
abstract fun bindViewModelFactory(kotlinViewModelFactory: KotlinViewModelFactory): ViewModelProvider.Factory
}
ViewModelKey.kt
@MustBeDocumented
@kotlin.annotation.Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
KotlinViewModelFactory.kt
@Singleton
class KotlinViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("unknown model class " + modelClass)
}
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
Я уже потратил много времени на обнаружение ошибки в моем коде, если кто-то может мне помочь в этом. :(
Ответы
Ответ 1
Мне просто не хватало добавления @JvmSuppressWildcards
до Provider<ViewModel>
@Singleton
class KotlinViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
...
}
Пусть Бог поможет всем нам с Kotlin + Dagger :)
Я написал статью, чтобы решить этот лабиринт Dagger, чтобы облегчить жизнь разработчикам:
https://medium.com/simform-engineering/stabbing-the-dagger-in-kotlin-merely-in-4-mins-977dba02fade
Ответ 2
В моем случае я забыл включить @Module(includes = [ViewModelModule::class])
в class AppModule