Saving UI States

保存UI状态

  • 处理简单的情况:onSaveInstanceState()
  • 管理更复杂的状态:分而治之
  • 恢复复杂的状态:重新组装

你做或者不做,保存UI状态,是用户体验的重要组成部分。无论用户是否旋转设备,用户重新启动应用程序,或系统关闭应用程序,activity保持用户期望的状态都是十分重要的。

在要保存的UI数据简单且轻量级的情况下,可以单独使用onSaveInstanceState()来保存状态数据。在您想要保留复杂数据的情况下,可以使用ViewModel对象,onSaveInstanceState()方法和持久本地存储的组合。

本页讨论了每种方法。

1. 处理简单的情况:onSaveInstanceState()

onSaveInstanceState()回调被设计用来在系统停止并稍后重新创建该控制器时,存储相对少量的数据,然后轻松地重新加载如活动或片段等UI控制器的状态。这个回调是为了处理两种情况:

  • 由于内存限制,程序处于后台时系统会 杀死应用程序的进程。
  • 发生配置更改,例如屏幕旋转或更改输入语言。

正如这两种情况所暗示的,onSaveInstanceState()在系统停止活动但未完成活动的情况下被调用。例如,如果用户离开应用程序几个小时,并且系统从内存中弹出相关进程,则系统调用缺默认实现onSaveInstanceState()来保存具有ID的每个UI控制器。之后,当用户返回到应用程序时,系统 将从保存的状态恢复活动

注意:当用户明确地关闭活动或者在其他情况下finish()被调用时onSaveInstanceState()是不会被调用。

系统会自动为您保存和恢复大量UI数据:默认实现 onSaveInstanceState()保存有关活动视图层次结构状态的信息,例如EditText部件中的文本或ListView部件的滚动位置 。您也可以通过覆盖onSaveInstanceState()回调来将自定义数据保存到此bundle中。如果您重写此方法以保存未被每个实体捕获的附加信息,则应该调用默认实现,除非您准备自行保存每个实体的状态。

onSaveInstanceState()不是用来存储大量数据,比如位图,或者需要冗长序列化或反序列化的复杂数据结构。如果序列化的对象很复杂,则序列化可能消耗大量内存。由于在配置更改期间,此进程发生在主进程中,因此如果时间过长的序列化可能会导致丢帧和卡顿。
因此,不要使用onSaveInstanceState()保存复杂的数据结构,确保将这些结构存储在本地持久性存储中;创建数据后尽快存储数据是一个好主意,以尽量减少丢失的可能性。然后,使用onSaveInstanceState()为每个这些对象存储唯一的ID。

本文档的下一部分提供了有关保留更复杂的数据的更多细节。

3.管理复杂的状态:分而治之

如果在活动结束时需要保留更复杂的数据结构,则可以通过将工作划分为多种类型的存储机制来有效地保存和恢复UI状态。

用户可以通过两种常规方式离开活动,导致用户可能期望得到两种不同的结果:

  • 用户完全关闭活动。如果用户将活动从“最近”屏幕上滑下,从活动向上导航或从活动中退出,用户可以完全关闭该活动。在这些情况下的假设是用户已经永久导航离开活动,并且如果他们再次打开活动,则他们将期望从干净状态开始。

  • 用户旋转手机或将该活动置于后台,然后返回。例如,用户执行搜索,然后按下主页按钮或接听电话。当他们返回到搜索活动时,他们希望能够像以前一样找到搜索关键字和结果。

要在任何情况下实现复杂数据结构的行为,可以一起使用本地持久性,ViewModel类和onSaveInstanceState()方法。这些方法中的每一种都存储活动中使用的不同类型的数据。

  • 本地持久性:如果您打开并关闭活动,则存储您不想丢失的所有数据。
    • 示例:歌曲对象的集合,其中可能包含音频文件和元数据。
  • ViewModel:存储在内存中与UI控制器显示关联的所需的所有数据。
    • 示例:最近搜索的歌曲对象和最近的搜索查询。
  • onSaveInstanceState():存储少量数据,以便在系统停止时轻松地重新加载活动状态,然后重新创建UI控制器。而不是在这里存储复杂的对象,坚持在本地存储复杂的对象,并使用onSaveInstanceState()存储在这些对象的唯一ID。
    • 例如:存储最近的搜索查询。

举个列子,一个activity可以让你搜索你的歌曲库。以下是应如何处理不同的事件:

当用户添加歌曲时,ViewModel立即使这些数据本地化。如果这个新添加的歌曲是要在用户界面中显示的,您还应该更新ViewModel对象中的数据以反映歌曲的添加。记住在主线程中做所有的数据库插入。

当用户搜索歌曲时,无论您从数据库为UI控制器加载任何复杂的歌曲数据,都应立即存储在ViewModel 对象中。您还应该将搜索查询本身保存在ViewModel对象中。

当活动进入后台时,系统调用onSaveInstanceState()。您应该将搜索查询保存在onSaveInstanceState()包中。这少量的数据很容易保存。这也是将活动恢复到当前状态所需的全部信息。

4. 恢复复杂的状态:重新组装

当用户返回活动时,有两种可能的方案来重新创建活动:

  • 该活动在被系统停止后重新创建。该活动将查询保存在一个onSaveInstanceState()包中,并将查询传递给ViewModel。ViewModel了解到没有缓存搜索结果,然后使用给定的搜索查询代表加载搜索结果。
  • 活动是在配置更改后创建的。活动已经将查询保存在onSaveInstanceState()包中,并且ViewModel已经将搜索结果缓存起来。将onSaveInstanceState()包中的查询传递给ViewModel,这意味着已经加载了必要的数据,并且不需要重新查询数据库。

注意:当一个活动最初创建时,onSaveInstanceState()不包含任何数据,并且该ViewModel对象是空的。当你创建 ViewModel对象的时候,你传递一个空的查询,告诉ViewModel对象没有要加载的数据。因此,活动以空的状态开始。

根据您的活动实施情况,您可能根本无需使用onSaveInstanceState()。
例如,浏览器可能会在退出浏览器之前使用户回到他们正在查看的确切网页。如果您的活动按照这种方式进行,您可以放弃使用onSaveInstanceState(),而是在本地保留所有内容。在歌曲搜索示例中,这可能意味着将最近的查询保留在Shared Preferences中。

另外,当您使用intent打开一个活动时,当配置发生变化以及系统恢复活动时,这些附加信息都会被传递给活动。如果搜索查询是作为一个intent extra传入的,则可以使用extras bundle而不是onSaveInstanceState()bundle。

在这两种情况下,您仍然会使用 ViewModel来避免在配置更改期间从数据库重新加载数据的浪费。

你可能感兴趣的:(Saving UI States)