I don't understand why am I getting this error:
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)
}
}
}
I have already wasted much amount of time on finding error in my code, if someone can help me on this. :(
Dagger 2 is the first to implement the full stack with generated code. The guiding principle is to generate code that mimics the code that a user might have hand-written to ensure that dependency injection is as simple, traceable and performant as it can be.
Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice. Note: Use Hilt for dependency injection on Android.
With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.
Dagger 2 is a compile-time android dependency injection framework that uses Java Specification Request 330 and Annotations. Some of the basic annotations that are used in dagger 2 are: @Module This annotation is used over the class which is used to construct objects and provide the dependencies.
I was just missing to add @JvmSuppressWildcards
before Provider<ViewModel>
@Singleton
class KotlinViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
...
}
May God help all of us with Kotlin + Dagger :)
I wrote an article to solve this maze of Dagger, so as to make developers life easy:
https://medium.com/simform-engineering/stabbing-the-dagger-in-kotlin-merely-in-4-mins-977dba02fade
In my case, I forgot to include @Module(includes = [ViewModelModule::class])
in class AppModule
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With