其实还有很多不错的选择。
first:人们往往会忘记的第一个是每个 ViewModel 都有一个 ViewModelfactory,这比拥有一个大型工厂要好得多。这就是我们所说的单一职责原则
class FirstViewModelFactory(val firstDependency: SomeClass, val secondDependency: SomeOtherClass): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
FirsViewModel(firstDependency, secondDependency) as T
}
}
在活动中:
val viewModel: FirstViewModel = ViewModelProvider(this, FirstViewModelFactory(first, second))[FirstViewModel::class.java]
第二:如果您希望所有 ViewModel 都只有一个工厂,您可以定义一个带有 lambda 的通用工厂:
class ViewModelFactory<VM: ViewModel>(val provider: () -> VM): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return provider() as T
}
}
并在活动或片段中像这样使用它:
val ViewModel: FirstViewModel = ViewModelProvider(this, ViewModelFactory<FirstViewModel>{
FirstViewModel(first, second)
})[FirstViewModel::class.java]
这实际上让您的生活更轻松。但还是可以改进的
第三:你可以告诉dagger如何为你提供FirstViewModel及其依赖。
如果您不知道如何使用匕首,请尝试学习它然后阅读此部分。
你需要告诉 dagger 你想要一个FirstViewModle 的实例。那个地方在AppComponent。
@Component(modules = [AppModule::class])
interface AppComponent {
val applicationContext: Context
val firstViewModel: FirstViewModel
...
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context): AppComponent
}
}
在你的 appModule 中,你需要告诉 dagger 如何使用 @Provides 注解来提供 FirstViewModel 的依赖关系。那么你需要在应用程序类中实例化你的匕首组件,有很多方法可以做到这一点,我只是使用工厂接口:
class MyApplication: Application() {
val component: AppComponent by lazy {
DaggerAppComponent.factory().create(applicationContext)
}
}
不要忘记在清单中添加MyApplication。
然后在您的活动中,您可以注入 viewModel 而无需担心依赖关系:
val appComponent = (application as MyApplication).appComponent
val viewModel: FirstViewModel = ViewModelProvider(this, ViewModelFactory<FirstViewModel>{
appComponent.firstViewModel
})[FirstViewModel::class.java]
您可以使用lazy 和扩展函数使其更加美观和可读,您最终可以拥有这样的东西:
private val viewModel: FirstViewModel by injectVmWith { appInjector.firstViewModel }
第四:你可以随时使用dagger的multibinding。有了这个,您将 ViewModelFactory 注入到活动或片段中,然后从中检索 viewModel。有了这个,你告诉 dagger 把你所有的 viewModel 放在一个地图中,然后把它注入到 ViewModelFactory。你通过注释来帮助 dagger 找到 viewModel。并且您还使用另一个注释告诉 dagger 他们的密钥是什么。您在另一个模块中完成所有这些操作,并且对于每个视图模型,您都需要在视图模型模块中添加一个函数。然后,您无需在大型工厂中使用 switch/case,而是告诉 dagger 根据其类型从地图中获取所需的视图模型。这是一个服务定位器(反?)模式。这本身就是另一个话题,这个答案已经太长了。参考this或this
总结:我认为如果你使用匕首,第三把绝对是赢家。多重绑定也很好,但是每次添加视图模型时,您都需要记住在 viewmodelModule 中添加一个函数(就像 Koin 一样)。如果您不使用匕首,我认为第二种方式是最好的,但您应该决定哪种方式最适合您。
Koin也很棒!