Kotlin dagger 2 Android ViewModel 注入错误
Posted
技术标签:
【中文标题】Kotlin dagger 2 Android ViewModel 注入错误【英文标题】:Kotlin dagger 2 Android ViewModel injection error 【发布时间】:2018-03-08 04:57:50 【问题描述】:我正在尝试在我的 android 应用程序上使用 dagger 2 从 arch android 库中注入新的 ViewModel。
从我在这个样本上看到的https://github.com/googlesamples/android-architecture-components/tree/e33782ba54ebe87f7e21e03542230695bc893818/GithubBrowserSample 我需要使用这个:
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
@Module
abstract class ViewModelModule
@Binds
@IntoMap
@ViewModelKey(LoginViewModel::class)
internal abstract fun bindLoginViewModel(viewModel: LoginViewModel): LoginViewModel
@Binds
@IntoMap
@ViewModelKey(MainMenuViewModel::class)
internal abstract fun bindSearchViewModel(viewModel: MainMenuViewModel): MainMenuViewModel
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@ApplicationScope
@Component(modules = arrayOf(ApplicationModule::class, NetworkModule::class, ViewModelModule::class))
interface ApplicationComponent
fun plusActivityComponent(activityModule: ActivityModule): ActivityComponent
fun inject(application: LISAApplication)
而我的工厂是:
@ApplicationScope
class ViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards 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)
但是项目没有编译:(我有这个错误(没有@Provides-annotated方法就无法提供Map<...>。):
Using Kotlin incremental compilation
:mobile:transformDataBindingWithDataBindingMergeArtifactsForDebug UP-TO-DATE
:mobile:kaptDebugKotlin
e: /Users/jaumard/LISAProjects/LISA/mobile/build/tmp/kapt3/stubs/debug/com/mylisabox/lisa/dagger/components/ApplicationComponent.java:6: error: [com.mylisabox.lisa.dagger.components.ActivityComponent.inject(com.mylisabox.lisa.common.BaseActivity)] java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
e:
e: public abstract interface ApplicationComponent
e: ^
e: java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
e: com.mylisabox.lisa.dagger.ViewModelFactory.<init>(creators)
e: com.mylisabox.lisa.dagger.ViewModelFactory is injected at
e: com.mylisabox.lisa.common.BaseActivity.factory
e: com.mylisabox.lisa.common.BaseActivity is injected at
e: com.mylisabox.lisa.dagger.components.ActivityComponent.inject(activity)
e: /Users/jaumard/LISAProjects/LISA/mobile/build/tmp/kapt3/stubs/debug/com/mylisabox/lisa/dagger/components/ActivityComponent.java:4: error: com.mylisabox.lisa.dagger.components.ActivityComponent scoped with @com.mylisabox.network.dagger.annotations.ActivityScope may not reference bindings with different scopes:
e:
知道如何解决这个问题吗?
【问题讨论】:
在 Kotlin 中使用@Binds
注释时遇到了类似的问题 - 我必须更改以返回带有 @Provides
的具体实现,而不是抽象方法。如果有人能提供解决方案就好了。
你好,马克,所以你的意思是你删除所有抽象方法并改用@Provides?女巫的意思是地图必须手动构建对吗?
为我找到答案,检查一下,希望它也对你有用
我的略有不同,我的抽象方法参数是接口实现类,返回类型是接口类型 - 虽然我可能已经倒退了,所以我会检查 - 为更新干杯用你的解决方案。
【参考方案1】:
好吧,我找到了问题,问题出在我的 ViewModelModule 下,我需要从我的抽象方法中返回 ViewModel,而不是直接返回我想要的类型。会变成这样:
@Module
abstract class ViewModelModule
@Binds
@IntoMap
@ViewModelKey(LoginViewModel::class)
internal abstract fun bindLoginViewModel(viewModel: LoginViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(MainMenuViewModel::class)
internal abstract fun bindSearchViewModel(viewModel: MainMenuViewModel): ViewModel
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
【讨论】:
我已经这样做了,但仍然失败。我必须用@JvmSuppressWildcards
注释注释 Provider<ViewModel>>
才能使其工作。 class ViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory
你说得对,@JvmSuppressWildcards 是强制性的,我没有把它放在我的答案中,因为它已经出现在我的问题的工厂代码中
嘿@jaumard 我遇到了同样的错误..尝试了仍然无法解决的确切答案..还有其他方法吗?
哼不像我所知道的对不起,我猜 lib 已经进化了,所以它可能需要更多的改变
最后添加 @JvmSuppressWildcards
是不够的,它仍然失败 Kotlin v1.3.31 解决方案在这里:youtrack.jetbrains.com/issue/KT-30979 只需将 kapt correctErrorTypes = true
添加到顶部的 app/build.gradle
dependencies
部分以上是关于Kotlin dagger 2 Android ViewModel 注入错误的主要内容,如果未能解决你的问题,请参考以下文章
dagger2 和 kotlin 的 Android 单元测试问题
没有Dagger2的Android Kotlin MVVM结构
如何在 android 中使用 dagger 对 kotlin 文件进行 UI 测试?
kotlin + Dagger2 :没有@Provides-annotated 方法就无法提供