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

Difference between by viewmodels and viewmodel creation using Factory?

我正在研究 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 的子class,那么您不需要工厂。 (或者,如果您的构造函数是上述任何一个加上 SavedStateHandle。)视图模型工厂是一个 class,它能够实例化具有更复杂构造函数的 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 构造函数。