正确保存Android视图状态(上)
原文链接:http://trickyandroid.com/saving-android-view-state-correctly/
注:以下翻译比较忠于原文
今天我们将谈论Android视图状态的保存和恢复。我想让我们专注于Android视图状态,因为我发现比起保存你的Activity或Fragment的状态,这个过程只是一个小技巧。而且我觉得在整个互联网我已经看够重新发明轮子(有时真的挺难看的)。
我们为什么需要保存视图状态?
很好的问题!我有很强的信念,移动应用程序可以帮助你解决存在的问题,不增加新的。 想象一下,一个非常复杂的设置页面如下:
当然,有一部分用户并不在意,也将很高兴接受再次完成表单。但是老实说,自己一个正确的操作被删除了(或者更糟-疯狂的拿着火把和干草叉的用户就开始按响了你的门铃)。
让我们做正确的事情,帮助我们的用户吧!这才是应该做的!我们需要保存用户的更改直到用户明确的要求我们不需要保存。
我要如何保存视图状态?
下面例子有一个的简单布局,TextView和Switch:超级简单的布局,你可以看到。
但是现在当我切换更改屏幕方向-然后我切换回了原来的状态:(
Android通常自动保存类似的视图状态。但为什么在我们的例子中它没有工作?
让我们退后一步,试图找出如何Android管理视图状态。正常的save/restore过程如下:
保存状态时:
1. saveHierarchyState(SparseArray<Parcelable> container) - Android framework在需要保存视图状态时调用,通常调用 dispatchSaveInstanceState().
2. dispatchSaveInstanceState(SparseArray<Parcelable> container) – 被saveHierarchyState()调用。内部调用 onSaveInstanceState()方法,并返回一个Parcelable类型表示当前View的状态。
3. Parcelable onSaveInstanceState() – 被dispatchSaveInstanceState()调用。在实现时需要覆盖此方法,已返回view的实际状态。
恢复状态时:
1. restoreHierarchyState(SparseArray<Parcelable> container) - Android framework在需要恢复视图状态时调用,这里包含一个包含之前保存的状态的SparseArray作为输入参数。
2. dispatchRestoreInstanceState(SparseArray<Parcelable> container) – 被restoreHierarchyState()调用,但是一个ViewGroup时,基于View ID遍历数组中的每个Parcelable元素,并传给到onRestoreInstanceState()作为输入参数,以恢复每个子view状态。
3. onRestoreInstanceState(Parcelable state) – 被dispatchRestoreInstanceState()调用。
理解这个过程很重要的一块是,容器是整个视图层次的共享。我们将看到一块为什么这么重要。
现在我们知道,因为视图的状态保存基于View的ID——如果没有ID的View将不被保存到容器。如果一个View没有ID-我们将无法恢复状态,因为我们不知道这个状态属于那个View。
看起来这就是为什么之前我们切换屏幕方向时状态不保存!让我们试着给Switch添加ID(和其他所有的view):
当我们再次旋转屏幕时,这正式我们想要的!这是可行的!在更改屏幕方向时,我们的view的状态得到了保存。这时我们的SparseArray看起来像:
正如你可以看到,每个有ID的View的状态被存储到了SparseArray容器。
你问这是怎么发生的-事实上我们并没有为View的状态提供任何Parcelable,答案是Android系统在做这些。Android系统知道如何保存它的内置控件的状态。
除了ID之外,你应该明确告诉Android系统你的View需要保存其状态。
这种做法可以简单的称作setSaveEnabled(true)。你通常不需要为内置插件做这个,但是如果你开发了自定义视图,你就需要手动enable了。
未完,待续 --