【问题标题】:Dagger2 compilation error in MVVM Factory when defining injector for fragment为片段定义注入器时,MVVM 工厂中的 Dagger2 编译错误
【发布时间】:2019-04-22 01:31:21
【问题描述】:

我有一个下一个根组件:

@Singleton
@Component(modules = [AndroidInjectionModule::class,
        AndroidSupportInjectionModule::class, 
        ActivityBuilderModule::class])
interface RootComponent : AndroidInjector<DaggerApplication> {
    fun inject(myApplication: MyApplication)
    override fun inject(photoPartyApplication: DaggerApplication)

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): RootComponent
    }
}

在 ActivityBuilderModule 中:

@Module
abstract class ActivityBuilderModule {

    @ContributesAndroidInjector(modules = [MainActivityModule::class,
            ViewModelModule::class])
    @ActivityScope
    abstract fun bindMainActivity(): MainActivity

    @ContributesAndroidInjector(modules = [SecondaryActivityModule::class,
            ViewModelModule::class,
            FragmentBuilderModule::class])
    @ActivityScope
    abstract fun bindSecondaryActivity(): SecondaryActivity

}

ViewModelModule 是一个简单的模块,可帮助在 ViewModel 类中进行构造函数注入,由特定实例之间的 @BindsViewModel 类型组成。

MainActivityModuleSecondaryActivityModule 为相应的活动定义了具体的依赖关系。

关键是当我添加这个 FragmentBuilderModule - 编译开始发出错误。堆栈跟踪是下一个:

错误:[Dagger/MissingBinding] some_package.SpecificDependency 不能在没有@Inject 构造函数或@Provides-annotated 方法的情况下提供。

公共抽象接口 RootComponent 扩展 dagger.android.AndroidInjector {

^

组件中存在具有匹配键的绑定:some_package.ActivityBuilderModule_BindMainActivity.MainActivitySubcomponent

some_package.SpecificDependency 被注入到 some_package.MainViewModel(specificDependency, …)

some_package.MainViewModel 在 some_package.ViewModelModule.mainViewModel(viewModel) 注入

Map<Class<? extends ViewModel>, Provider<ViewModel>> is injected at
      some_package.ViewModelFactory(viewModelProviders)

some_package.ViewModelFactory 在 some_package.ViewModelModule.bindViewModelFactory(factory) 注入

android.arch.lifecycle.ViewModelProvider.Factory 在 some_package.MyFragment.viewModelFactory 注入

some_package.MyFragment 在 dagger.android.AndroidInjector.inject(T) 处注入

[some_package.RootComponent → some_package.ActivityBuilderModule_BindSecondaryActivity.SecondaryActivitySubcomponent → some_package.FragmentBuilderModule_ProvideMyFragmentFactoryMyFragmentSubcomponent]

据我所知,Dagger 假设必须为Class&lt;? extends ViewModel&gt; -&gt; Provider&lt;ViewModel&gt;map 正确构建整个依赖关系图,如果某些ViewModels 落入factory,并且factory 是注入到组件中,然后如果组件将要求 any viewmodel必须交付。为了交付所有viewmodels,再次,所有依赖项都必须可用(这是不正确的,因为MainViewModel 的特定依赖项只能从MainModule 获得,这就是dagger 在堆栈跟踪之前所说的)。

是否有一种解决方法可以按需提供对Class&lt;? extends ViewModel&gt; -&gt; Provider&lt;ViewModel&gt;map 的依赖关系,而不是在编译时构建整个图(这会导致编译时错误)

【问题讨论】:

    标签: android android-fragments dagger-2


    【解决方案1】:

    首先在RootComponent处添加ViewModelModule

     @Singleton
     @Component(modules = [AndroidInjectionModule::class,
                AndroidSupportInjectionModule::class, 
                ActivityBuilderModule::class,
                ViewModelModule::class])                 // add this so you don't have to add for every activity
        interface RootComponent : AndroidInjector<DaggerApplication> {
            fun inject(myApplication: MyApplication)
            override fun inject(photoPartyApplication: DaggerApplication)
    
            @Component.Builder
            interface Builder {
                @BindsInstance
                fun application(application: Application): Builder
                fun build(): RootComponent
            }
        }
    

    现在在 ActivityBuilderModule 中只添加活动

     @Module
     abstract class ActivityBuilderModule {
    
        @ContributesAndroidInjector
        @ActivityScope
        abstract fun bindMainActivity(): MainActivity
     }
    

    现在在 ViewModelModule 中添加所有 ViewModel

     @Module
     abstract class ViewModelModule {
    
        @Binds
        @IntoMap
        @ViewModelKey(MainActivityModule::class)
        abstract fun bindMainActivityViewModel(mainActivityViewModel: MainActivityModule): ViewModel
    }
    

    添加 ViewModelKey

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

    和 ViewModelFactory

    @Singleton
    class KotlinViewModelFactory @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 {
                Timber.d(creator.toString())
                return creator.get() as T
            } catch (e: Exception) {
                throw RuntimeException(e)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多