【问题标题】:kotlin + Dagger2 : cannot be provided without an @Provides-annotated methodkotlin + Dagger2 :没有@Provides-annotated 方法就无法提供
【发布时间】:2018-08-04 04:54:25
【问题描述】:

我不明白为什么会出现此错误:

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)
        }
    }
}

如果有人可以帮助我解决此问题,我已经浪费了大量时间来查找代码中的错误。 :(

【问题讨论】:

  • 我认为你必须提供 splashViewModel: SplashViewModel & kotlinViewModelFactory: KotlinViewModelFactory
  • 查看这里关于Kotlin Wildcards
  • @DavidMedenjak 宾果游戏!!谢谢指点。

标签: android kotlin dagger-2


【解决方案1】:

我只是想在Provider&lt;ViewModel&gt; 之前添加@JvmSuppressWildcards

@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

【讨论】:

  • 有同样的问题,好吧,添加@JvmSuppressWildcards 现在获取ApiService 不能提供没有@Provides 方法。 :|男人!
  • 就我而言,这是 Kotlin 1.3.30 的问题。尝试将版本更新到 1.3.31。
【解决方案2】:

就我而言,我忘记在class AppModule 中包含@Module(includes = [ViewModelModule::class])

【讨论】:

    猜你喜欢
    • 2019-06-21
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    相关资源
    最近更新 更多