使用工厂创建视图模型和视图模型之间的区别?

时间:2021-06-02 17:40:17

标签: android kotlin android-viewmodel android-mvvm

我正在学习 ViewModel 以将其应用于 MVVM 设计模式。

在视图模型创建中,有一个使用 by viemodels() 的方法和一个使用 ViewModelProvider.Factory 的方法。

by viewModels() 创建一个 ViewModel object

ViewModelProvider.Factory 还会创建 Viewmodel objects

这两者有什么区别?

另外,在一些示例代码中,我看到了注释3中的代码,它同时使用了by viewModels()factory。这是什么意思?

class WritingRoutineFragment : Fragment() {
    private val viewModel: WriteRoutineViewModel by viewModels() // 1
    private lateinit var viewModelFactory: WriteRoutineViewModelFactory

//  private val viewModel: WriteRoutineViewModel by viewModels(
//        factoryProducer = { viewModelFactory } // 3.What does this code mean?
//  )

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        _binding = FragmentWritingRoutineBinding.inflate(inflater, container, false)
        viewModelFactory = WriteRoutineViewModelFactory()
//        viewModel = ViewModelProvider(this, viewModelFactory).get(WriteRoutineViewModel::class.java) // 2
        return binding.root
    }

1 个答案:

答案 0 :(得分:3)

如果您的 ViewModel 有一个零参数构造函数,或者如果它有一个构造函数,其中它的唯一参数是 Application 类型并且它是 AndroidViewModel 的子类,那么您不需要工厂。 (或者,如果您的构造函数是上述任何一个加上 SavedStateHandle。)视图模型工厂是一个能够实例化具有更复杂构造函数的 ViewModel 的类。

在不使用委托的情况下实例化您的 ViewModel 时,您必须对属性使用 lateinit var,因为您在 onCreateView 之前无法实例化它。

如果您的 ViewModel 不需要工厂,那么在没有委托的情况下完成它的过程将如下所示:

class WritingRoutineFragment : Fragment() {
    private lateinit var viewModel: WriteRoutineViewModel

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        //...
        viewModel = ViewModelProvider(this, viewModelFactory).get(WriteRoutineViewModel::class.java)
        //...
    }
}

如果它确实需要一个工厂,它看起来像这样,你必须实例化一个工厂并将它传递给 ViewModelProvider 构造函数:

class WritingRoutineFragment : Fragment() {
    private lateinit var viewModel: WriteRoutineViewModel

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        //...
        viewModel = ViewModelProvider(this, WriteRoutineViewModelFactory()).get(WriteRoutineViewModel::class.java)
        //...
    }
}

委托允许您在声明站点的 val 中更简洁地执行此操作,因此您无需在 onCreateView 中对视图模型属性进行任何设置。它会在第一次使用该属性时懒惰地创建 ViewModel。优点是代码更简洁清晰(lateinit var 将属性与其声明分开并使其可变,即使它永远不会改变)。

所以当不需要工厂时,上面的代码看起来像:

class WritingRoutineFragment : Fragment() {
    private val viewModel: WriteRoutineViewModel by viewModels()
}

如果你确实需要一个工厂,它看起来像这样。你传递给它一个实例化工厂的函数,这很容易用 lambda 来完成:

class WritingRoutineFragment : Fragment() {
    private val viewModel: WriteRoutineViewModel by viewModels { WriteRoutineViewModelFactory() }
}

您示例中的代码有一个额外的属性来保存工厂,这是不必要的复杂化,因为您永远不需要直接访问它。您示例中的工厂有一个空构造函数也很奇怪,因为如果工厂没有任何状态,那么它就没有数据可以传递给 ViewModel 构造函数。