繁体   English   中英

Android 创建viewModel的不同方式 object 什么时候使用哪一种?

[英]Android different ways to create viewModel object which one to use when?

我最近开始使用 ViewModel 和 AndroidViewModel,我看到初始化 viewModel 实例有不同的方法,对我来说一切正常,我只想知道什么时候使用哪个? 我应该在哪里初始化viewModel object? 以下都是获取 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>()

对我来说最简单和最简单的是第 3、第 4 和第 5 种方法,但是我不知道所有五种方法有什么区别,也请告诉我是否有任何其他方法或最佳方法来初始化我的 viewModel object,我在声明全局变量时对其进行初始化,是否可以在声明时进行初始化,或者应该在某个生命周期方法中完成?

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

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

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


45是一回事,只是在不同的地方指定了类型(你只需要一个声明,另一个将被推断)。 它们是来自 KTX 库的代表,它们与3执行相同的操作,但它们在 IMO 中更具可读性 - 特别是如果您正在混合范围,例如使用by viewModels来获取 Fragment 自己的 VM,也可以by activityViewModels让活动的虚拟机与该片段和其他片段共享数据。

它们也是lazy委托(据我所知),这意味着 VM 仅在首次访问时才被实例化。 这通常会在生命周期的后期发生(而不是在 object 首次构建时)。 我不确定在构造时初始化 VM是否有问题,但我见过的所有官方示例似乎都在onCreate (或附近)中获取它

如果有人在寻找深入的答案,请检查这个,这里我们有以下方法来创建或获取 viewModel object:

  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这意味着 object 没有延迟加载,因此开发人员有责任仅在创建活动或片段时创建视图模型 object附加到活动,这意味着前三种方法(1、2、3)不能在全局 scope 中使用,如果在全局 scope 中使用,则该变量必须是带有lateint或 Z37A6259CC0C1DAE29BD19A78668 初始化的 var , 2, 3) 必须发生在 onCreate 或 onViewCreated 中(在片段的情况下)。

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

val myViewModel4: MyViewModel by viewModels()

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

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

如果您的视图 model 中有多个参数并且不使用任何依赖注入,则可以使用 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, 2, 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 function 这意味着两者正在做同样的事情,如果我们想要多个参数,最好选择这两种方法但是我们必须重写ViewModelProvider.NewInstanceFactory来创建我们自己的工厂,就像在这里完成的那样

现在是第三个:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM