如何使用一个 ViewModelFactory 为 Dagger 提供所有 ViewModel
How to use one ViewModelFactory to provide for all ViewModels with Dagger
如何实现通用 ViewModel 工厂来为我的所有项目 ViewModel 提供服务?
需要明确的是,我的 ViewModels 具有依赖性(作为构造函数参数)
嗯,有一个叫做 GithubBrowser,但它不是教程,而是一个项目。你应该知道 dagger for android 可以做到这一点。或者,您可以检查以下代码:
@Singleton
class DaggerViewModelFactory @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)
}
}
}
这部分将为您的整个应用程序创建一个 "generic" 视图模型。以这种方式, ViewModel
是用分配的参数创建的。之后,您需要在单例模块中实现工厂模块,并将其包含在组件中。
@Component(
modules = [... ViewModelModule::class]
)
interface AppCompoenent{}
现在是有趣的部分:
@Suppress("unused")
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(MyViewModel::class)
abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel
@Binds
abstract fun bindsViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory
}
由于 dagger 支持多重绑定,您可以根据需要自由绑定 ViewModels
。
ViewModelKey:
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
您基本上是将值放入哈希图中。这些值是您的 ViewModel
。
点击构建! Done.After 你只是在你的片段中注入了一个 ViewModelProvider.Facory
。在你的 ViewModel
中你可以做:
class MyViewModel @Inject constructor(
private val dependency: YourDependency
) : ViewModel() {}
在评论中明确说明您的要求。首先,没有具体需要知道DaggerViewModelFactory
内部发生了什么,虽然我不建议这样学习,因为我是"Always knowing what's happening"的铁杆粉丝。仅供参考,DaggerViewModelFactory
只是一个 class,它接受一个 Map
,每个 class 扩展 ViewModel
作为键,并且 class 依赖项作为一个值。使用 Provider<T>
时,Dagger 知道如何找到这些依赖项,但在您调用 provider.get()
之前不会将它们带给您。将其视为延迟初始化。
现在检查modelClass.isAssignableFrom(it.key)
。它只是检查 class 是否真的扩展了 ViewModel
.
关于你的第二个问题,理解第一部分很重要。由于 Dagger
支持多重绑定,这意味着您可以使用 Map<Key, Value>
提供依赖项。例如,Map<HomeViewModel, Provider<ViewModel>>
基本上会告诉 dagger 给我 HomeViewModel
的依赖项。 Dagger 会说:如何知道哪些是 HomeViewModel
依赖项?然后您回答:我已经为此定义了一个 Key,它就是 HomeViewModel
class 本身。所以你只需要创建一个注释,将它与 @Binds
和 @IntoMap
结合起来,在后台 Dagger 将只执行 map.put(HomeViewModel::class, AndDependencies)
.
如何实现通用 ViewModel 工厂来为我的所有项目 ViewModel 提供服务? 需要明确的是,我的 ViewModels 具有依赖性(作为构造函数参数)
嗯,有一个叫做 GithubBrowser,但它不是教程,而是一个项目。你应该知道 dagger for android 可以做到这一点。或者,您可以检查以下代码:
@Singleton
class DaggerViewModelFactory @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)
}
}
}
这部分将为您的整个应用程序创建一个 "generic" 视图模型。以这种方式, ViewModel
是用分配的参数创建的。之后,您需要在单例模块中实现工厂模块,并将其包含在组件中。
@Component(
modules = [... ViewModelModule::class]
)
interface AppCompoenent{}
现在是有趣的部分:
@Suppress("unused")
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(MyViewModel::class)
abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel
@Binds
abstract fun bindsViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory
}
由于 dagger 支持多重绑定,您可以根据需要自由绑定 ViewModels
。
ViewModelKey:
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
您基本上是将值放入哈希图中。这些值是您的 ViewModel
。
点击构建! Done.After 你只是在你的片段中注入了一个 ViewModelProvider.Facory
。在你的 ViewModel
中你可以做:
class MyViewModel @Inject constructor(
private val dependency: YourDependency
) : ViewModel() {}
在评论中明确说明您的要求。首先,没有具体需要知道DaggerViewModelFactory
内部发生了什么,虽然我不建议这样学习,因为我是"Always knowing what's happening"的铁杆粉丝。仅供参考,DaggerViewModelFactory
只是一个 class,它接受一个 Map
,每个 class 扩展 ViewModel
作为键,并且 class 依赖项作为一个值。使用 Provider<T>
时,Dagger 知道如何找到这些依赖项,但在您调用 provider.get()
之前不会将它们带给您。将其视为延迟初始化。
现在检查modelClass.isAssignableFrom(it.key)
。它只是检查 class 是否真的扩展了 ViewModel
.
关于你的第二个问题,理解第一部分很重要。由于 Dagger
支持多重绑定,这意味着您可以使用 Map<Key, Value>
提供依赖项。例如,Map<HomeViewModel, Provider<ViewModel>>
基本上会告诉 dagger 给我 HomeViewModel
的依赖项。 Dagger 会说:如何知道哪些是 HomeViewModel
依赖项?然后您回答:我已经为此定义了一个 Key,它就是 HomeViewModel
class 本身。所以你只需要创建一个注释,将它与 @Binds
和 @IntoMap
结合起来,在后台 Dagger 将只执行 map.put(HomeViewModel::class, AndDependencies)
.