Saving UI States

相对用户体验而言,如何保留当前UI界面的状态都是很关键的一部分,不管你做还是不做。不论用户是旋转屏幕,重启应用,或者系统关掉了应用,如何保持用户所期望的界面状态是很重要的。

当要保存少量且轻量的UI数据时,可以考虑使用onSaveInstanceState()。如果想要保存相对比较复杂的数据时,可以同时使用ViewModel对象,以及onSaveInstanceState(),以及持久化本地数据。

接下来将介绍如何去保存UI状态数据。

Manging simpler cases:onSaveInstanceState()

使用onSaveInstanceState()处理简单的场景
onSaveInstanceState()回调函数用于存储相对较少量的数据,以便在系统停止并稍后重新创建该控制器时轻松地重新加载UI控制器的状态,如Activity或Fragment。这个回调主要处理以下两种情况:
1. 由于内存的限制,系统会杀掉后台的应用进程
2. 配置变化,比如说屏幕旋转,修改输入语言等
以上两种情况意味着,系统在回调这个方法是,Activity被停止,但是还没有完全结束。举个例子,当用户离开应用几个小时后,系统会从内存中把相关的进程弹出,
系统会回调默认的onSaveInstanceState()实现来保存每个拥有ID的UI Controller。然后,当用户返回到应用时,系统将恢复之前保存的Activity状态。

注:有两种情况下onSaveInstanceState()不会被调用,一个是用户明确要关闭当前的Activity,另一个就是某些场景下直接调用onFinished()。

系统会自动保存和恢复大部分的UI数据;onSaveInstanceState()的默认实现中保存了Activity的视图树,比如EditText控件中的输入文本以及ListView控件当前滑动的列表项。开发过程中,我们可以通过重写onSaveInstanceState()回调方法,将一些自定义数据保存到Bundle中。如果您打算重写此方法以保存未被每个实体捕获的附加信息,应该调用默认实现,除非你准备自行保存每个实体的状态。

onSaveInstanceState()为保存大量数据而设计的,比如Bitmaps或者需要冗长的序列化和反序列化的复杂的数据结构。复杂的数据在序列化过程会消耗大量的内存。因为在设备配置发生变化的时候,这个过程是在主线程中执行的,长时间序列化会引起掉帧或者卡顿。因此,使用本地数据持久化来代替onSaveInstanceState()存储复杂的数据结构;比较好的一个方法就是在数据创建的时候就进行保存,然后使用onSaveInstanceState()保存对应数据的ID。

Managing more complex states : divide and conquer

使用分而治之的方法管理复杂的状态
当你需要比较复杂的数据结构需要在Activity结束时保存,可以通过多种不同存储方式实现,这样能更有效的保存和恢复这些数据。

用户可以通过两个比较常规的方式离开Activity,这两个方式会使用户期望得到不同的结果:
1. 用户完全关闭了Activity。如果用户将Activity从当前的屏幕中滑下,或者向上导航或返回当前Activity,都可以完全关闭这个Activity。在这种情况下,就可以假设用户想要拥有离开或推出当前Activity,当他们重新进入或打开这个Activity时,他们期望看到的是一个全新的页面,而不是之前的退出的状态。
2. 用户旋转手机或者将当前Activity切换至后台,然后再重新切回前台。举个例子,用户点击了搜索按钮然后点击了Home键,或者用户接听了一个电话。当返回后,用户期望搜索界面中保留着之前的输入,并显示和之前一样的搜索结果。

为了实现上述场景中复杂数据结构保存,可以结合使用本地持久化,ViewModel和onSaveInstanceState()方法。每种方法保存activity中不同类型的数据。

  • 本地持久化:保存那些不论你打开或关闭当前activity都不想遗漏的所有数据。
  • ViewModel:保存和UI Controller展示相关的所有数据(保存在内存中)。比如最近查询的歌曲或者搜索结果。
  • onSaveInstanceState():保存少量的便于快速加载Activity,当系统停止Activity后又重新重建。通过本地数据库保存复杂数据,然后通过onSaveInstanceState()保存对应的数据索引ID,比如保存最近的搜索结果。

以搜索歌曲库为例子,在一个Activity中,可以进行搜索歌曲库的功能,然后我们需要做那些操作来实现数据的保存与恢复:

当用户添加一首歌曲时,ViewModel快速实现数据的本地持久化,如果新加的歌曲需要在当前的页面中显示,就需要更新ViewModel响应该歌曲已经添加成功。记住所有的数据库操作在子线程中执行。

当用户搜索一首歌曲,不论歌曲的数据多复杂,都需要从数据库中加载到ViewModel中,搜索的数据也必须保存在ViewModel中。

当activity退至后台,系统会回调onSaveInstanceState()。需要在onSaveInstanceState()保存用户的查询ID。这个少量的数据容易存储。这也是activity显示到前台后需要显示的所有信息。

Restoring complex states:reassembling the pieces

恢复复杂的状态:组装相关数据
当用户重新返回Activity时,有两个可能的场景需要重新创建activity:

  • activity是有系统停止然后重建。activity将搜索的id保存在onSaveInstanceState()的bundle中,此时需要传给ViewModel,ViewModel发现没有缓存数据,然后就会通过所有去本地数据库加载搜索结果。
  • activity是有设备配置变化重建的。activity将搜索的id保存在onSaveInstanceState()的bundle中,此时需要传给ViewModel,ViewModel发现有缓存数据,然后就不需要去查询本地数据库了。

注:当activity被首次创建时,onSaveInstanceState()中的bundle数据为空,ViewModel数据也为空。当创建ViewModel时需要传递一个空的搜索id,告诉ViewModel不需要加载任何数据。因此activity将显示一个全新的状态。

基于activity的实现,也许不必在onSaveInstanceState()中保存任何数据。比如浏览器可能会将用户返回到之前退出的那个页面。如果你的activity实现了这个功能就可以不使用onSaveInstanceState,直接将数据进行本地持久化。在歌曲搜索的例子中,意味着持久化最近的搜查到Shared Preferences中。

另外,当你通过Intent启动一个Acitivity时,
无论是配置更改还是系统恢复Activity,都会将其附加Bundle交传给Activity。如果搜索查询是作为intent的额外信息传入的,则可以使用extras bundle而不使用onSaveInstanceState()bundle。

不论上述的哪一种场景,都需要使用ViewModel避免重复的从数据库中加载数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值