如何使用dagger2限制有关ViewModelFactory的范围?

时间:2019-06-10 18:14:03

标签: android dagger-2 android-viewmodel

我使用的是Google推荐的带有Dagger2的Android体系结构组件。我遵循了Google Sample,但这并不完美。

此解决方案确实简化了注入,但是如果我的ViewModels依赖数据库,则在创建ViewModel时需要Dao。目前,工厂已绑定到AppModule以提供全局使用。因此,必须在AppModule中提供ViewModel才能添加到地图。因此,道就是全球化的。

由于Dao只能用于某些特殊活动,因此在全球范围内创建Dao既浪费又不便。

我试图将bindViewModel函数的定义移至ActivityModule,但出现了以下错误:

 [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.
public abstract interface AppComponent {
                ^
      java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
          com.chenhe.platform.viewmodel.MyViewModelFactory(creators)
      com.chenhe.platform.viewmodel.MyViewModelFactory is injected at
......

AppModule:

@Module(subcomponents = [LocalWatchFaceComponent::class], includes = [ViewModelModule::class])
class AppModule(private val context: Context) {

    @Provides
    @Singleton
    fun provideContext(): Context = context

    @Provides
    @Singleton
    fun provideAppDataBase(): AppDatabase = AppDatabase.getInstance(context)

    // I want move code below to ActivityModule. But Dao was needed by viewmodel by factory map
    @Provides
    fun provideLocalWatchFaceDao(database: AppDatabase) = database.localWatchFaceDao()
}

ViewModel:

class LocalWatchFaceViewModel @Inject constructor(
        private val appCtx: Context,
        localWatchFaceRepository: LocalWatchFaceRepository) : ViewModel() {}

MapKey:

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

ViewModelModule:

@Module
abstract class ViewModelModule {
    @Binds
    abstract fun bindViewModelFactory(factory: MyViewModelFactory): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(LocalWatchFaceViewModel::class)
    abstract fun bindLocalWatchFaceViewModel(viewModel: LocalWatchFaceViewModel): ViewModel
}

工厂:

@Singleton
class MyViewModelFactory @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)
        }
    }
}

是否有计划优雅地划分范围?

0 个答案:

没有答案