使用 onSaveInstanceState() 和 ViewModel 保存活动的状态

Posted

技术标签:

【中文标题】使用 onSaveInstanceState() 和 ViewModel 保存活动的状态【英文标题】:Saving activity's state with onSaveInstanceState() and ViewModel 【发布时间】:2019-07-17 08:22:18 【问题描述】:

阅读本文后,我对 ViewModel 有一些疑问:

https://developer.android.com/topic/libraries/architecture/saving-states

这里说您应该结合使用ViewModel 来进行配置更改(如屏幕旋转),并使用onSaveInstanceState() 来处理活动被销毁然后重新创建以保存 UI 的所有其他情况状态。

我的问题是我们如何知道在调用onCreate(Bundle) 时恢复状态的方式 - 我应该使用 ViewModel 还是应该使用接收到的包作为参数?当配置发生变化时,onSaveInstanceState()也会被调用,显然onCreate()总是被调用。

如果我只从 ViewModel 恢复状态,它不会始终保留正确的数据(因为活动可能由于配置更改以外的其他原因而被破坏)。如果我只使用我保存在onSaveInstanceState() 中的捆绑包,那我为什么要使用ViewModel 开头呢?

【问题讨论】:

【参考方案1】:

我认为将这些来源视为一个链条很好。 您有 2 个数据源 - ViewModel,速度更快但寿命较短,保存的实例状态较慢但寿命更长。

规则很简单 - 尝试使用您的 ViewModel,如果未填充,请使用来自 onSaveInstanceState() 的包。

当您在 onCreate() 中执行 val model = ViewModelProviders.of(this).get(MyViewModel::class.java) 时,您可以检查是否获得了新的 viewModel 实例。然后,如果它是一个新实例(即它的数据字段为空),您可以从您的包中获取一些基本数据,如内容 ID,并根据该 ID 从后端或数据库中获取数据,用它填充您的新 ViewModel 并然后从 ViewModel 填充您的活动(如果您使用的是 LiveData,这将非常自然)。

下次调用 onCreate 时,您重复该过程,从 ViewModel 填充您的活动,或者使用 Bundle 中的数据填充您的 ViewModel,然后从您的 ViewModel 填充您的活动。

更新: 实际上,官方docs 中描述了非常相似的方法。唯一的区别是您将捆绑包传递给 ViewModel 并由它决定是否需要获取数据,我没有具体说明这种机制。

【讨论】:

如果我在 ViewModel 中拥有的只是初始化为默认值的原语怎么办?我无法判断这是因为该实例是一个新实例,还是这些只是正确的值。无论如何,总的来说,您的建议听起来像是一种解决方法.. 好吧,在这种特殊情况下,您需要实现一些字段来指示您的 ViewModel 不是新创建的,或者将一些数据添加到您的状态包并使用它。如果你只有一堆原语要保存,你不会从使用 ViewModel 中得到太多,在这种情况下,只需实现实例状态并使用它。 ViewModel 可帮助您保留复杂的下载数据或用户生成的数据。 还要检查答案更新,它链接到官方方法。 所以据我了解,它也只是说您应该检查所需的数据是否已经存在.. 是否有某种系统标志告诉您您在 onCreate 中的原因?或者可能是一个标志,告诉您 ViewModel 是否刚刚创建? 我认为当您第一次使用 ViewModelProviders 创建 ViewModel 时,框架不会在 ViewModel 上调用任何参数构造函数,因此您可以将其用作 ViewModel 是新的指标。

以上是关于使用 onSaveInstanceState() 和 ViewModel 保存活动的状态的主要内容,如果未能解决你的问题,请参考以下文章

onSaveInstanceState() 和 onRestoreInstanceState()

onSaveInstanceState 的目的

使用 onSaveInstanceState() 和 ViewModel 保存活动的状态

分离不触发 onSaveInstanceState() 的片段

在哪里可以使用 onSaveInstanceState 参数传递不同的Activity?

Android onSaveInstanceState()恢复数据