Я использую компонент архитектуры Android с Dagger2, который рекомендован Google. Я следовал за Google Sample , но он не идеален.
Это решение упрощает внедрение, но если мои ViewModels полагаются на базу данных, Dao был необходим при создании viewmodel. На данный момент фабрика была привязана к AppModule для обеспечения глобального использования. Поэтому ViewModel должен быть предоставлен в AppModule для добавления на карту. Таким образом, Дао также будет глобальным.
Поскольку Дао может использоваться только в какой-то специальной деятельности, его создание в глобальном масштабе является пустой тратой и неудобно в управлении.
Я попытался переместить определение функции 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
}
Factory:
@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)
}
}
}
Есть ли план изящно разделить область?