Android不同的方式创建viewModel对象时使用哪一个



我最近开始使用ViewModel和AndroidViewModel,我发现初始化ViewModel实例有不同的方法,对我来说一切都很好,我只想知道什么时候使用哪一种?我应该在哪里初始化viewModel对象?以下是获取viewModel实例的不同方法,对我来说很有效:

val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
val myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)
val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)
val myViewModel4: MyViewModel by viewModels()
val myViewModel5 by viewModels<MyViewModel>()

对我来说,最简单和最简单的是第三、第四和第五种方法,但我不知道这五种方法有什么区别,也请告诉我是否有其他方法或最佳方法来初始化我的viewModel对象,我在声明全局变量时对其进行初始化,可以在声明时进行初始化吗,还是应该在一些生命周期方法中进行初始化?

如果有人在寻找深度答案,请检查此项,我们有以下方法来创建或获取viewModel对象:

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)

  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

  3. val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

  4. val myViewModel4: MyViewModel by viewModels()

  5. val myViewModel5 by viewModels<MyViewModel>()

所有人都做同样的事情,唯一的两个关键区别是:

  1. 使用延迟加载和不使用延迟加载的viewModel初始化
  2. 具有多个参数和无参数的viewModel

让我们在lazy loading and without lazy loading中看到这一点,前三个没有委托by,这意味着该对象没有延迟加载,所以它是开发人员只有在创建活动或将片段附加到活动时才有责任创建viewModel对象,这意味着前三种方法(1、2、3)不能在全局范围使用,如果在全局范围内使用,则变量必须具有lateint或null初始化的var,以及初始化(方法1、2、3)必须在onCreate或onViewCreated(如果是片段)。

因此,创建viewModel对象的最佳方法是使用委托by(4,5),两者相同,但语法有点不同,我选择4是因为它简单易读。

val myViewModel4: MyViewModel by viewModels()

by委托提供了延迟加载实例的灵活性,您可以在全局范围内定义viewModel并摆脱样板代码,如果您尝试在没有委托的情况下在全局范围初始化viewModel,应用程序将崩溃,因为viewModel将在创建活动之前尝试初始化(它不会延迟加载viewModel实例)。

现在让我们看看如何使用多个参数延迟加载,问题中没有提到6th方法。

如果您的视图模型中有多个参数,并且不使用任何依赖项注入,则可以使用ViewModelFactory实现,然后延迟加载它:

val myViewModelWithParm: MyViewModel by viewModels { MyViewModelFactory(application, "param1", "param2") }

ViewModelFactory实现:

class MyViewModelFactory(val application: Application, val param1: String, val param2: String) :
ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(application, param1, param2) as T
}
}

到目前为止,我们已经清楚了委托初始化(4,5),以及它与(1,2,3)的区别,现在让我们看看前3种方法(1,3)之间的区别。

让我们先检查1和2。

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

它们的关键区别是一个使用ViewModelProvider.NewInstanceFactory,另一个使用了ViewModelProvider.AndroidViewModelFactory,所以我检查了这两个类的源代码,发现ViewModelProvider.AndroidViewModelFactory实际上是ViewModelProvider.NewInstanceFactory的实现,它覆盖了create函数,这意味着两者都在做相同的事情,如果我们想要多个参数,最好选择这两种方法,但为此,我们必须覆盖ViewModelProvider.NewInstanceFactory来创建我们自己的工厂,就像这里所做的那样

现在是第三个:

val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

当我们的ViewModel中没有多个参数并且不想延迟加载对象时,这就是1和2的简单形式。

注意:我强烈推荐方法4或5(两者相同,但语法不同),因为这是最合适和最佳的编写方法,如果没有多个参数,如果有多个参数的话,可以通过实现ViewModelProvider.Factory使用答案中提到的方法6。

3是获取(并在必要时创建)不带构造函数参数的ViewModel的标准方法。在内部,执行1传递一个调用空构造函数(NewInstanceFactory())的工厂。

AndroidViewModelViewModel的一个子类,它会自动传入application引用,以防您需要访问应用程序上下文等内容。因此,即使您的AndroidViewModel没有参数,创建它的工厂也需要传入application,这就是2正在执行的操作。

默认情况下,这一切都是通过3为您处理的-如果您的VM需要配置一些额外的参数,您只需要定义并使用工厂。


45是同一回事,只是在不同的地方指定了类型(您只需要一个声明,就会推断出另一个)。它们是来自KTX库的委托,与3做同样的事情,但它们更具可读性IMO-尤其是当您混合作用域时,比如使用by viewModels来获得片段自己的VM,还使用by activityViewModels来获得活动的VM,以便与该片段和其他片段共享数据。

它们也是lazy委托(据我所知!),这意味着VM只有在第一次访问时才会被实例化,这通常会在生命周期的后期发生(而不是在第一次构建对象时)。我不确定是否存在在构建时初始化VM的问题,但我看到的所有官方示例似乎都是在onCreate(或大约)中获取的

相关内容

最新更新