kotlin + Dagger2 :没有@Provides-annotated 方法就无法提供
Posted
技术标签:
【中文标题】kotlin + Dagger2 :没有@Provides-annotated 方法就无法提供【英文标题】:kotlin + Dagger2 : cannot be provided without an @Provides-annotated method 【发布时间】: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 宾果游戏!!谢谢指点。 【参考方案1】:我只是想在Provider<ViewModel>
之前添加@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])
【讨论】:
以上是关于kotlin + Dagger2 :没有@Provides-annotated 方法就无法提供的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin + Dagger2:不能在没有 @Inject 构造函数或 @Provides- 或 @Produces-annotated 方法的情况下提供
Dagger2 + Kotlin:lateinit 属性尚未初始化
Dagger2 Qualifier 不适用于 Kotlin?
dagger2 和 kotlin 的 Android 单元测试问题
Android kotlin 使用Dagger2报错 InvocationTargetException 不能生成DaggerXXComponent