定义片段的注入器时,MVVM Factory中的Dagger2编译错误

时间:2018-11-19 16:26:07

标签: android android-fragments dagger-2

我还有一个根组件:

@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类中进行构造函数注入,并且由特定实例和@Binds类型之间的ViewModel组成。

MainActivityModuleSecondaryActivityModule为相应的活动定义特定的依赖关系。

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

  

错误:[Dagger / MissingBinding] some_package。如果没有@Inject构造函数或@Provides注释的方法,则无法提供SpecificDependency。

     

公共抽象接口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假设必须为map的{​​{1}}正确地构建整个依赖关系图,如果某些Class<? extends ViewModel> -> Provider<ViewModel>落入{{1} },并且将ViewModels注入到组件中,那么如果该组件要求任何 factory,则必须将其交付。同样,为了交付所有factory,所有依赖项都必须可用(这是不正确的,因为viewmodel的特定依赖项仅可从viewmodels获得,这就是匕首在堆栈跟踪之前说。)

有没有解决方法,可以根据需要提供对MainViewModel的{​​{1}}的依赖关系,而不是在编译时构建整个图形(这会导致编译时错误)

1 个答案:

答案 0 :(得分:0)

  

首先在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)
        }
    }
}