在android中使用“by viewModels()”与“ViewModelProvider(this).get(ViewModel::class.java)”进行视图模型初始化

Posted

技术标签:

【中文标题】在android中使用“by viewModels()”与“ViewModelProvider(this).get(ViewModel::class.java)”进行视图模型初始化【英文标题】:View model initialization using "by viewModels()" vs "ViewModelProvider(this).get(ViewModel::class.java)" in android 【发布时间】:2021-03-28 19:54:20 【问题描述】:

我们可以使用初始化ViewModel

private val viewModel: CharactersViewModel by viewModels()

viewModel = ViewModelProvider(this).get(CharactersViewModel::class.java)

Herer CharactersViewModel 是我们的 ViewModel 类。我的问题是什么时候使用哪个? 两者是否包含相同的目的?我已经阅读了 ViewModel 的 android 官方文档。文档说 by viewModels() Kotlin property delegate。但遗憾的是没能看懂。谁能帮我理解这个?

【问题讨论】:

【参考方案1】:

他们都做同样的事情,但第一个有区别优势。 Kotlin 属性委托使用Lazy Initialization 的思想。在Wikipedia 你可以找到它的简短定义:

在计算机编程中,延迟初始化是延迟对象的创建、值的计算或其他一些昂贵的过程直到第一次需要它的策略。它是一种惰性求值,专门指对象或其他资源的实例化。

因此,当您使用您提到的第一种方法时,您利用了惰性属性。这意味着 ViewModel 实例仅在第一次访问时创建。

以下面的代码为例:

class YourFragment : Fragment() 

    private val viewModel: CharactersViewModel by viewModels()

    // other codes ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
        super.onViewCreated(view, savedInstanceState)
        
        // doing some view initialization ...

        viewModel.someLiveData.observe(viewLifecycleOwner) 
            // ...
        
    

如果viewModel.someLiveData.observe(viewLifecycleOwner) 是第一次触摸viewModel 字段,它的实例化将在那里发生。 (创建CharactersViewModel 实例)

因此,使用对象的延迟初始化(如视图模型)可以减少片段的启动影响,从而加快加载和显示其内容,而不是直接初始化它们。

【讨论】:

已经好几个小时了!现在我看到我有一个“=”而不是“:”导致错误“分类器'ViewModel'没有伴随对象,因此必须在此处初始化”【参考方案2】:

这两个语句是相等的。

Kotlin 关键字 by 只是为您节省了一些代码,省去了使用反射访问您的虚拟机的痛苦,并且看起来更干净,如果您像我一样。

要么或者应该为你做这项工作:)

【讨论】:

【参考方案3】:

要添加到已经提到的答案,

lateinit 修饰符告诉类型检查器一个 var 属性将在使用前“通过魔法”初始化,因此不需要给定一个可为空的类型。它会阻止类型检查器帮助您正确初始化属性。相反,初始化中的编程错误会在稍后的运行时由异常报告。

它适用于 Kotlin 代码与使用反射将值插入类型检查器和可见性修饰符后面的字段的传统 Java 框架交互时。

我们应该尽量避免在我们的代码中使用lateinit,如果可能的话,在这种情况下你应该使用

private val viewModel: CharactersViewModel by viewModels()

【讨论】:

以上是关于在android中使用“by viewModels()”与“ViewModelProvider(this).get(ViewModel::class.java)”进行视图模型初始化的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 12 中使用 WorkManager

如何在 android 应用程序中使用 OSM 地图。?有啥教程可以学习在android中使用OSM吗?

如何在Mac中使用Android SDK

在 Android 中使用 Intent 在活动中传递 android 位图数据

无法在 Android 中使用 Android Crop 图像裁剪库

Android:如何在 Android 中使用 tensorflow lite 扩展图像的维度