【问题标题】:Dagger/MissingBinding java.util.Map<java.lang.Class<? extends ViewModel>,Provider<ViewModel>> cannot be provided without an @Provides-annotated methodDagger/MissingBinding java.util.Map<java.lang.Class<? extends ViewModel>,Provider<ViewModel>> 不能在没有 @Provides 注释的方法的情况下提供
【发布时间】:2019-09-04 07:00:39
【问题描述】:

这就是我试图提供我的ViewModelFactory的方式:

@Suppress("UNCHECKED_CAST")
@Singleton
class ViewModelFactory @Inject constructor(
    private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

这就是我绑定ViewModelFactory的方式:

@Suppress("unused")
@Module
abstract class ViewModelModule  {
    @Binds
    internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class)
    internal abstract fun mainViewModel(viewModel: MainViewModel): ViewModel
}

我在构建过程中收到以下错误:

di/Injector.java:9: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.

来自我的Activity,我正在尝试以这种方式接收ViewModelFactory

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

【问题讨论】:

    标签: android kotlin dependencies dagger-2 dagger


    【解决方案1】:

    我最近遇到了同样的问题。 版本 科特林:1.3.40 匕首:2.23.2 我尝试按照本文中提到的解决方案和here

    但似乎没有一个工作。 Dagger 的注释处理器不能很好地与 KAPT 配合使用,出于同样的原因,构建失败了。这也在 Kotlin issue 上进行了更新。

    对我来说,将 ViewModelKeyViewModelFactory 都转换为 java 是可行的。 对于 Dagger,可以在 here 找到跟踪问题。

    更新 添加@JvmSuppressWildcards 解决了这个问题。代码如下所示:

    private val providers: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
    

    【讨论】:

    • 我所有的代码都在 kotlin 中。将 ViewModelKey 和 ViewModelFactory 都转换为 java 工作。谢谢。添加@JvmSuppressWildcards 无效
    • 这太棒了我的兄弟。
    • 你这个男人。 @JvmSuppressWildcards 获胜。
    【解决方案2】:

    在深入挖掘之后,我发现了问题所在。 它与我正在使用的代码完全无关。这是Kotlin 1.3.30

    Here有关它的更多信息。

    降级到Kotlin 1.3.21 解决了这个问题。

    【讨论】:

    【解决方案3】:

    首先 ViewModelFactory 不应该是单例。无论如何要解决这个问题,你应该有:

    • ViewModelFactory

      class ViewModelFactory @Inject constructor( private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { val creator = creators[modelClass] ?: creators.entries.firstOrNull { modelClass.isAssignableFrom(it.key) }?.value ?: throw IllegalArgumentException("unknown model class $modelClass") try { @Suppress("UNCHECKED_CAST") return creator.get() as T } catch (e: Exception) { throw RuntimeException(e) } } }

    • 在你的模块类中绑定这个工厂

      @Binds abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    • 有一个 ViewModelKey

      @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FUNCTION) @MapKey annotation class ViewModelKey(val value: KClass<out ViewModel>)

    • 将您的 viewModel 绑定到所需的模块中

      @Binds @IntoMap @ViewModelKey(MyViewModel::class) abstract fun bindCustomViewModel(viewModel: MyViewModel): ViewModel

    • 然后实现并使用您的 viewModel

      @Inject lateinit var viewModelFactory: ViewModelFactory

      private val viewModel: MyViewModel by viewModels { viewModelFactory }

    此解决方案已使用 Kotlin 1.3.72 和最新版本的 Dagger2 进行测试。 也请查看https://github.com/android/architecture-components-samples/tree/master/GithubBrowserSample

    希望这会对你有所帮助。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 2021-05-05
    • 2021-06-11
    • 1970-01-01
    相关资源
    最近更新 更多