Android 创建 viewModel 对象的不同方法在什么时候使用哪一种?
Android different ways to create viewModel object which one to use when?
我最近开始使用 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>()
对我来说最简单最简单的是第3、4和5种方法,但是我不知道这五种方法有什么区别,如果还有其他方法或最佳初始化方法,请告诉我我的 viewModel 对象,我在声明它时对全局变量进行了初始化,可以在声明时初始化还是应该在某些生命周期方法中完成?
3 是获取(并在必要时创建)没有构造函数参数的 ViewModel 的标准方法。在内部,这是在做 1 来传递调用空构造函数的工厂 (NewInstanceFactory()
)。
AndroidViewModel
是 ViewModel
的子类,它会自动传入 application
引用,以防您需要访问应用程序上下文等内容。所以即使你的AndroidViewModel没有参数,创建它的工厂也需要传入一个application
,这就是2所做的。
默认情况下,使用 3 即可为您解决所有问题 - 如果您的 VM 需要配置一些额外参数,您只需定义和使用工厂。
4 和 5 是一回事,只是在不同的地方指定了类型(你只需要一个声明和其他将被推断)。它们是 KTX 库的代表,它们做的事情与 3 相同,但在我看来它们的可读性要高得多——尤其是当你混合作用域时,比如使用 [=15] =] 获取片段自己的 VM,以及 by activityViewModels
获取 Activity 的 VM 以与该片段和其他片段共享数据。
它们也是 lazy
委托(据我所知!)这意味着 VM 仅在首次访问时才被实例化,这通常会在生命周期的后期发生(而不是何时该对象首先被构造)。我不确定 是 在构造时初始化 VM 的问题,但我看到的所有官方示例似乎都在 onCreate
(或附近)中获取它
如果有人在寻找深入的答案,请检查这个,这里我们有以下创建或获取 viewModel 对象的方法:
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
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
让我们看看 lazy loading and without lazy loading
,前三个没有委托 by
,这意味着该对象没有延迟加载,所以它是开发人员
仅当创建 activity 或片段附加到 activity 时才负责创建 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 将在创建 activity 之前尝试初始化(它不会延迟加载 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, 2, 3) 的区别).
我们先检查 1 和 2。
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
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
我最近开始使用 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>()
对我来说最简单最简单的是第3、4和5种方法,但是我不知道这五种方法有什么区别,如果还有其他方法或最佳初始化方法,请告诉我我的 viewModel 对象,我在声明它时对全局变量进行了初始化,可以在声明时初始化还是应该在某些生命周期方法中完成?
3 是获取(并在必要时创建)没有构造函数参数的 ViewModel 的标准方法。在内部,这是在做 1 来传递调用空构造函数的工厂 (NewInstanceFactory()
)。
AndroidViewModel
是 ViewModel
的子类,它会自动传入 application
引用,以防您需要访问应用程序上下文等内容。所以即使你的AndroidViewModel没有参数,创建它的工厂也需要传入一个application
,这就是2所做的。
默认情况下,使用 3 即可为您解决所有问题 - 如果您的 VM 需要配置一些额外参数,您只需定义和使用工厂。
4 和 5 是一回事,只是在不同的地方指定了类型(你只需要一个声明和其他将被推断)。它们是 KTX 库的代表,它们做的事情与 3 相同,但在我看来它们的可读性要高得多——尤其是当你混合作用域时,比如使用 [=15] =] 获取片段自己的 VM,以及 by activityViewModels
获取 Activity 的 VM 以与该片段和其他片段共享数据。
它们也是 lazy
委托(据我所知!)这意味着 VM 仅在首次访问时才被实例化,这通常会在生命周期的后期发生(而不是何时该对象首先被构造)。我不确定 是 在构造时初始化 VM 的问题,但我看到的所有官方示例似乎都在 onCreate
(或附近)中获取它
如果有人在寻找深入的答案,请检查这个,这里我们有以下创建或获取 viewModel 对象的方法:
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
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
让我们看看 lazy loading and without lazy loading
,前三个没有委托 by
,这意味着该对象没有延迟加载,所以它是开发人员
仅当创建 activity 或片段附加到 activity 时才负责创建 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 将在创建 activity 之前尝试初始化(它不会延迟加载 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, 2, 3) 的区别).
我们先检查 1 和 2。
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
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
.