首页 > 解决方案 > MVVM:根据用例使用不同的 ViewModel 实现

问题描述

我有一个应该在多个用例中重用的片段,例如称为AddOrEditRecipeFragment,这个片段可用于创建或编辑配方,因为无论您创建或编辑配方,它都是相同的 UI。

但我想使用一个AddReceipeViewModelEditRecipeViewModel实例,具体取决于用例,它由片段上的 FragmentArgument 标识。两者都AddReceipeViewModel实现EditRecipeViewModel了相同的接口,所以我目前做的是:

private val viewModel: MyViewModelInterface by lazy {
    val mode = // ... just get a flag from the arguments which indicates which mode we are in
    val vm: MyViewModelInterface = when(mode) {
        Mode.EDIT -> { val vm: EditRecipeViewModel by activityViewModel(); vm }
        Mode.ADD -> { val vm: AddRecipeViewModel by activityViewModel(); vm }
    vm
}

这感觉非常错误,因为片段知道需要知道所有可能的实现MyViewModelInterface。有谁知道对此有更好的解决方案?

谢谢

标签: androidandroid-viewmodelandroid-mvvm

解决方案


您可以创建一个factory并将模式传递给工厂,让逻辑决定要实例化哪个视图模型,factory因此片段仅取决于接口。

在你的片段中添加这个

private val factory = ViewModelFactory() // inject it instead if using DI
private val viewModel: MyVieModelInterface by activityViewModels {
    factory
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val mode = // get mode from arguments
    factory.mode = mode
}

abstract class MyVieModelInterface : ViewModel() /* rename as it's not an interface */ {

}

class ViewModelFactory : ViewModelProvider.Factory {

    lateinit var mode: Mode

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T = if (modelClass.isAssignableFrom(MyVieModelInterface::class.java)) {
        when (mode) {
            Mode.EDIT -> EditViewModel(/* stuff here */)
            Mode.ADD -> AddViewModel(/* stuff here */)
        }
    } else {
        throw IllegalArgumentException("Unknown ViewModel class [$modelClass]")
    }
}

推荐阅读