MVVM:根据用例使用不同的 ViewModel 实现

MVVM: Use different ViewModel Implementation depending on Use-case

我有一个片段应该在多个用例中重复使用,例如名为 AddOrEditRecipeFragment,此片段可用于创建或编辑食谱,因为无论您创建或编辑食谱,它都是相同的 UI。

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

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 的所有可能实现。有人知道更好的解决方案吗?

谢谢

您可以创建一个 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]")
    }
}