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&lt;ViewModel&gt;&gt; 才能使其工作。 class ViewModelFactory @Inject constructor(private val creators: Map&lt;Class&lt;out ViewModel&gt;, @JvmSuppressWildcards Provider&lt;ViewModel&gt;&gt;) : 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 方法就无法提供

Android Kotlin:错误未解决参考:DaggerAppComponent

HasActivityInjector 无法在 android dagger 2 中解决