简体   繁体   English

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

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

I recently started with the ViewModel and AndroidViewModel, I see there are different approach to initialise a viewModel instance, for me all works fine, I just want to know which one to use when?我最近开始使用 ViewModel 和 AndroidViewModel,我看到初始化 viewModel 实例有不同的方法,对我来说一切正常,我只想知道什么时候使用哪个? and where should I initialise the viewModel object?我应该在哪里初始化viewModel object? following all are the different approach to get the viewModel instance and works for me:以下都是获取 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>()

The easiest and most simple for me are 3rd, 4th and 5th, however I don't know what is the difference in all the five approaches, also please let me know if there any other way or optimal way to initialise my viewModel object, I do the initialisation on the global variable while declaring it, is it okay to initialise at the declaration time or it should be done inside some lifecycle method?对我来说最简单和最简单的是第 3、第 4 和第 5 种方法,但是我不知道所有五种方法有什么区别,也请告诉我是否有任何其他方法或最佳方法来初始化我的 viewModel object,我在声明全局变量时对其进行初始化,是否可以在声明时进行初始化,或者应该在某个生命周期方法中完成?

3 is the standard way to fetch (and create if necessary) a ViewModel with no constructor parameters. 3是获取(并在必要时创建)没有构造函数参数的 ViewModel 的标准方法。 Internally, that's doing 1 to pass a factory that calls the empty constructor ( NewInstanceFactory() ).在内部,这是1传递一个调用空构造函数( NewInstanceFactory() )的工厂。

An AndroidViewModel is a subclass of ViewModel that automatically passes in an application reference, in case you need access to things like the application context. AndroidViewModelViewModel的子类,它会自动传入application引用,以防您需要访问应用程序上下文等内容。 So even if your AndroidViewModel has no parameters, the factory that creates it needs to pass in an application , which is what 2 is doing.所以即使你的 AndroidViewModel 没有参数,创建它的工厂也需要传入一个application ,这就是2正在做的事情。

This is all taken care of for you by default using 3 - you only need to define and use a factory if your VM needs to be configured with some extra parameters.默认情况下,这一切都使用3为您处理 - 如果您的 VM 需要配置一些额外的参数,您只需要定义和使用工厂。


4 and 5 are the same thing, just with the type specified in a different place (you only need one declaration and the other will be inferred). 45是一回事,只是在不同的地方指定了类型(你只需要一个声明,另一个将被推断)。 They're delegates from the KTX libraries, and they do the same thing as 3 , but they're much more readable IMO - especially if you're mixing scopes, like using by viewModels to get a Fragment's own VM, and also by activityViewModels to get the Activity's VM to share data with that and other Fragments.它们是来自 KTX 库的代表,它们与3执行相同的操作,但它们在 IMO 中更具可读性 - 特别是如果您正在混合范围,例如使用by viewModels来获取 Fragment 自己的 VM,也可以by activityViewModels让活动的虚拟机与该片段和其他片段共享数据。

They're also lazy delegates (as far as I'm aware,) meaning the VM only gets instantiated when it's first accessed.它们也是lazy委托(据我所知),这意味着 VM 仅在首次访问时才被实例化。 which is generally going to happen later in the lifecycle (instead of when the object is first constructed).这通常会在生命周期的后期发生(而不是在 object 首次构建时)。 I'm not sure if there is a problem initialising the VM on construction, but all of the official examples I've seen seem to fetch it in onCreate (or thereabouts)我不确定在构造时初始化 VM是否有问题,但我见过的所有官方示例似乎都在onCreate (或附近)中获取它

In case anyone looking for in depth answer, please check this, here we have the following way to create or get the viewModel object:如果有人在寻找深入的答案,请检查这个,这里我们有以下方法来创建或获取 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>()

All do the same thing, the only two key differences is:所有人都做同样的事情,唯一的两个关键区别是:

  1. The viewModel initialisation with lazy loading and without lazy loading.使用延迟加载和没有延迟加载的 viewModel 初始化。
  2. The viewModel with multiple parameter and no parameters.多参数无参数的viewModel。

Lets see this wrt the lazy loading and without lazy loading , the first three are without the delegate by that means there is no lazy loading of that object, so it's the developer responsibility to create the viewModel object only when activity is created or the fragment is attached to the activity, that means the first three approach(1, 2, 3) can't be used at global scope, if used at global scope the variable must be a var with lateint or null initialisation, and the initialisation(approach 1, 2, 3) must happen in the onCreate or onViewCreated(in case of fragment).让我们看看lazy loading and without lazy loading ,前三个没有委托by这意味着 object 没有延迟加载,因此开发人员有责任仅在创建活动或片段时创建视图模型 object附加到活动,这意味着前三种方法(1、2、3)不能在全局 scope 中使用,如果在全局 scope 中使用,则该变量必须是带有lateint或 Z37A6259CC0C1DAE29BD19A78668 初始化的 var , 2, 3) 必须发生在 onCreate 或 onViewCreated 中(在片段的情况下)。

Therefor the best way to create the viewModel object is using the delegate by (4, 5), both are same with a bit different syntax, I choose 4 because of it's simplicity and readability.因此,创建 viewModel object 的最佳方法是使用 (4, 5) 的by ,两者相同,但语法略有不同,我选择 4 是因为它简单易读。

val myViewModel4: MyViewModel by viewModels()

The by delegate gives the flexibility to lazy load the instance and you can define the viewModel at global scope and get ride off the boilerplate code, if you try to initialise the viewModel at global scope without the delegate the app will crash since the viewModel will try to initialise before the activity is created(it will not lazy load the viewModel instance). by委托提供了延迟加载实例的灵活性,您可以在全局 scope 定义 viewModel 并摆脱样板代码,如果您尝试在没有委托的情况下在全局 scope 初始化 viewModel,则应用程序将崩溃,因为 viewModel 将尝试在创建活动之前进行初始化(它不会延迟加载 viewModel 实例)。

Now let's see how to lazy load with multiple parameters, the 6th approach not mention in the question.现在让我们看看如何使用多个参数进行延迟加载,问题中没有提到6th方法。

If you have multiple parameters in your view model and not using any dependency injection, you can use a ViewModelFactory implementation and then lazy load it:如果您的视图 model 中有多个参数并且不使用任何依赖注入,则可以使用 ViewModelFactory 实现,然后延迟加载它:

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

ViewModelFactory implementation: 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
    }
}

Till this point we are clear on the delegate initialisation(4, 5), and how it is different with(1, 2, 3) now let's see the difference on the top 3 approach(1, 2, 3).到目前为止,我们已经清楚了委托初始化 (4, 5),以及它与 (1, 2, 3) 的不同之处现在让我们看看前 3 种方法 (1, 2, 3) 的区别。

Let's first check 1 and 2.让我们首先检查 1 和 2。

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

The key difference in them is one uses ViewModelProvider.NewInstanceFactory and other uses ViewModelProvider.AndroidViewModelFactory , so I checked the source code of both the classes and found that ViewModelProvider.AndroidViewModelFactory is actually the implementation of ViewModelProvider.NewInstanceFactory which override the create function that means both are doing the same stuff, preferable both approach should be chosen if we want multiple parameters however for that we have to override ViewModelProvider.NewInstanceFactory to create our own factory like it's done here它们之间的主要区别是一个使用ViewModelProvider.NewInstanceFactory而另一个使用ViewModelProvider.AndroidViewModelFactory ,所以我检查了这两个类的源代码,发现ViewModelProvider.AndroidViewModelFactory实际上是ViewModelProvider.NewInstanceFactory的实现,它覆盖了create function 这意味着两者正在做同样的事情,如果我们想要多个参数,最好选择这两种方法但是我们必须重写ViewModelProvider.NewInstanceFactory来创建我们自己的工厂,就像在这里完成的那样

Now comes the third one:现在是第三个:

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

This is the simple form of 1 and 2 when we don't have multiple parameters in our ViewModel and don't want to lazy load the object.当我们的 ViewModel 中没有多个参数并且不想延迟加载 object 时,这是 1 和 2 的简单形式。

Note: I highly recommend the approach 4 or 5(both are same with different syntax), since this is the most suitable and optimal to write, if you don't have multiple arguments, in case you have multiple arguments you can use the approach 6 mentioned in the answer by implementing ViewModelProvider.Factory .注意:我强烈推荐方法 4 或 5(两者语法不同),因为这是最适合和最佳编写的方法,如果您没有多个 arguments,如果您有多个 arguments,您可以使用该方法6 通过实现ViewModelProvider.Factory在答案中提到。

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

相关问题 在Android中进行异步服务调用的方法? 什么时候使用? - Ways of making async service calls in Android? and when to use which? 在Android中创建复选框列表的不同方法 - different ways to create checkbox list in android 哪一个是更快的颜色过滤或在Android中使用不同的drawable? - Which one is faster Color Filtering or use different drawables in android? 如何在viewModel中使用双向绑定 - How to use two-ways binding in viewModel 使用片段的不同方式 - Different ways to use Fragments android第一次在ViewModel中初始化LiveData怎么办? 使用哪个工厂? - How to initialize the LiveData in ViewModel for the first time in android? and which factory to use? Android:如何以不同的方式从json对象获取jsonarray - Android : how to get jsonarray from json object in different ways 何时在Android上使用本地存储,推荐使用哪一个? - When to use Local storage on Android, and which one is recommended? Android适配器-使用哪个? - Android Adapters - Which One To Use? 将单个 object 传递给 Android 中的 ViewModel 时,是否应该使用 Kotlin 流? - Should Kotlin Flows be used when passing a single object to ViewModel in Android?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM