如何使用一个 ViewModelFactory 为 ViewModel 提供 Dagger

Dav*_*vid 3 java android viewmodel kotlin dagger

如何实现一个ViewModelFactory来提供我的项目ViewModels及其对整个项目的依赖?

cor*_*her 5

嗯,有一个叫做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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这部分将为您的整个应用程序创建一个“通用”视图模型。以这种方式,ViewModel创建带有指定参数的 。之后,您需要在单例模块中实现工厂模块,并将其包含在组件中。

@Component(
    modules = [... ViewModelModule::class]
)
interface AppCompoenent{}
Run Code Online (Sandbox Code Playgroud)

现在有趣的部分:

    @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
}
Run Code Online (Sandbox Code Playgroud)

由于 Dagger 支持多重绑定,因此您可以随意绑定ViewModels

视图模型键:

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

您基本上是将值放入哈希图中。这些值是您的ViewModel.

命中构建!完成。之后,您只需ViewModelProvider.Facory在片段中注入一个。比在ViewModel你可以做的:

class MyViewModel @Inject constructor(
    private val dependency: YourDependency
) : ViewModel() {}
Run Code Online (Sandbox Code Playgroud)

明确您对评论的要求。首先,没有特别需要知道里面发生了什么DaggerViewModelFactory,虽然我不建议这样学习,因为我是“总是知道发生了什么”的忠实粉丝。仅供参考,这DaggerViewModelFactory只是一个类,它接受Map每个扩展ViewModel为键的类,以及该类的依赖项作为值。使用Provider<T>Dagger 时知道如何找到这些依赖项,但尚未将它们带给您,直到您调用provider.get(). 把它想象成一个懒惰的初始化。

现在检查modelClass.isAssignableFrom(it.key). 它只是检查该类是否真的 extends ViewModel

至于你的第二个问题,理解第一部分很重要。由于Dagger支持多重绑定,这意味着您可以使用Map<Key, Value>. 例如, aMap<HomeViewModel, Provider<ViewModel>>基本上会告诉 dagger 给我HomeViewModel的依赖项。Dagger 会说:如何知道哪些是HomeViewModel依赖项?你回答:我已经为此定义了一个 Key,它是HomeViewModel类本身。因此,您只需创建一个注释,将其与@Binds和结合@IntoMap,然后在后台 Dagger 将仅执行map.put(HomeViewModel::class, AndDependencies).

  • 当你是初学者时,这有点高级。如果您想学习基础知识,我自己有一篇关于 dagger 的文章:https://medium.com/@stavro96/keep-it-simple-with-dagger-2-241d32e14de (2认同)