美文网首页
ViewModel初识

ViewModel初识

作者: 一缕阳忆往昔 | 来源:发表于2019-12-31 16:19 被阅读0次

    问题

    潜在的挑战是,Android Activity生命周期具有很多状态,并且由于配置更改,单个Activity可能会在这些不同状态之间循环多次。

    图片来自官网

    当“活动”经历所有这些状态时,您可能还需要将临时 UI 数据保存在内存中。我将定义临时UI数据作为UI所需的数据。示例包括用户输入的数据,运行时生成的数据或从数据库加载的数据。这些数据可以是位图图像,RecyclerView所需的对象列表,或者在这种情况下是篮球得分。

    以前,您可能曾经 onRetainCustomNonConfigurationInstance 在配置更改期间保存此数据,然后在另一端将其解析获取。但是,如果您的数据不需要知道或管理“活动”所处于的生命周期状态,那会不会更好呢?除了scoreTeamA 将数据存储在 Activity 内,而不是将其存储在 Activity 内,而是将其存储在Activity之外的其他地方,该怎么办?这是ViewModel类的目的。

    在下图中,您可以看到一个活动的生命周期,该活动经历一个轮换然后最终完成。ViewModel 的生命周期显示在关联的Activity生命周期旁边。请注意,ViewModels 可以轻松地与 Fragment 和 Activity 结合使用,我将它们称为UI控制器。本示例重点介绍活动。

    图片来自官网

    从您首次请求ViewModel时(通常在onCreateActivity中)到活动完成并销毁为止,ViewModel 存在。onCreate在Activity的生命周期内可能会多次调用(例如,旋转应用程序时),但ViewModel会在整个过程中保留下来。

    一个非常简单的例子

    设置和使用 ViewModel 分为三个步骤:

    1. 通过创建扩展 ViewModel 的类,将数据与UI控制器分离

    2. 设置 ViewModel 和UI控制器之间的通信

    3. 在 UI 控制器中使用 ViewModel

    步骤1:创建一个ViewModel类

    注意:要创建 ViewModel ,首先需要添加正确的生命周期依赖项。看看这里如何。

     // ViewModel and LiveData
     implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
     // alternatively - just ViewModel
     implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" 
     // For Kotlin use lifecycle-viewmodel-ktx
    

    通常,您将为应用程序中的每个屏幕创建一个ViewModel类。这个ViewModel类将保存与屏幕关联的所有数据,并具有用于存储的数据的getter和setter。这会将代码显示出来,以显示 UI(在“Activities”和“Fragments”中实现)与数据(现在位于ViewModel中)之间。因此,让我们为Court-Counter中的一个屏幕创建一个ViewModel类:

    class ScoreViewModel : ViewModel() {
    
        var scoreTeamA: Int = 0
    
        var scoreTeamB: Int = 0
    }
    

    步骤2:关联控制器和ViewModel

    您的UI控制器(又称“Activity”或“Fragment”)需要了解您的ViewModel。这样,您的UI控制器就可以在发生UI交互时显示数据并更新数据,例如,按下按钮以增加在Court-Counter中的团队得分。

    但是,ViewModels 不应保留对Activity,Fragment或Context的引用。此外,ViewModels不应包含包含对UI控制器(例如Views)的引用的元素,因为这将创建对Context 的间接引用。

    您不应该存储这些对象的原因是 ViewModels 的寿命超过了特定的UI控制器实例-如果您将Activity旋转3次,则您已经创建了三个不同的Activity实例,但是只有一个ViewModel

    考虑到这一点,让我们创建此UI控制器/ ViewModel关联。您将要在UI Controller中为ViewModel创建一个成员变量。对于Court-Counter,它是这样的:

    import androidx.activity.viewModels
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        private val viewModel: ScoreViewModel by viewModels()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            tvOne.text = viewModel.scoreTeamA.toString()
            tvTwo.text = viewModel.scoreTeamB.toString()
    
            btAdd.setOnClickListener {
                viewModel.scoreTeamA += 1
                tvOne.text = viewModel.scoreTeamA.toString()
            }
            Log.d("MainActivity", "onCreate 执行了")
        }
    }
    

    注意:“ ViewModels中没有上下文”规则有一个例外。有时您可能需要一个Application上下文 (而不是Activity上下文)来与诸如系统服务之类的东西一起使用。可以将应用程序上下文存储在ViewModel中,因为应用程序上下文与应用程序生命周期相关联。这不同于与活动生命周期相关联的活动上下文。实际上,如果需要应用程序上下文,则应扩展 AndroidViewModel 这只是一个包含应用程序引用的 ViewModel。

    步骤3:在UI控制器中使用ViewModel

    要访问或更改UI数据,现在可以在ViewModel中使用数据。这是新onCreate方法的示例,以及通过向A组增加一个点来更新分数的方法:

    import androidx.activity.viewModels
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        private val viewModel: ScoreViewModel by viewModels()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            tvOne.text = viewModel.scoreTeamA.toString()
            tvTwo.text = viewModel.scoreTeamB.toString()
    
            btAdd.setOnClickListener {
                viewModel.scoreTeamA += 1
                tvOne.text = viewModel.scoreTeamA.toString()
            }
            Log.d("MainActivity", "onCreate 执行了")
        }
    }
    

    专家提示: ViewModel也可以与另一个架构组件LiveData很好地配合使用,在本系列文章中我将不做深入探讨。使用LiveData的额外好处是它是可观察的:当数据更改时,它可以触发UI更新。您可以在此处了解有关LiveData的更多信息。

    相关文章

      网友评论

          本文标题:ViewModel初识

          本文链接:https://www.haomeiwen.com/subject/kwzboctx.html