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



我正在研究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
}

如果您的 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中对视图模型属性进行任何设置。它将在首次使用该属性时延迟创建视图模型。优点是代码更简洁明了(lateinit var将属性与其声明分开,并使其可变,即使它永远不会改变)。

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

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

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

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

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

最新更新