Activity/Fragment 状态缓存和恢复的最佳实践

来源:互联网 发布:windows刷新英文 编辑:程序博客网 时间:2024/05/22 12:21

The Real Best Practices to Save/Restore Activity’s and Fragment’s state
英文原文:https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en

几个月前我发布过一篇关于Fragment缓存和恢复状态的文章:Probably be the best way (?) to save/restore Android Fragment’s state so far . 收到了许多来自世界各地Android开发者的宝贵建议和反馈,在此对大家说声谢谢嗷☺。(这里的文章原文博主已经删除,国内有翻译,下文中的StatedFragment就是这篇文章中的最终产物,为的是更方便的实现Fragment状态的缓存和恢复,不过已经不推荐大家使用)。
但是StatedFragment的策略和官方设定的缓存策略是不一样的,因为官方设定的策略可能让开发者能更容易的理解Fragment的状态缓存和恢复,使其表现的像Activity那样能同时操控View和变量。为此我做了个实验来测试StatedFragment,以验证它是否更加容易理解?它的设计对开发者来说是否更加友好?经过两个月的测试,我想我已经得出结论了:虽然StatedFragment显得更容易理解,但同时它也带来了一个大问题,即它破坏了Android View的架构设计,可能在以后带来更多问题,并且,我也开始怀疑之前写的代码有点诡异… 因为这些原因,我决定从现在开始废弃掉StatedFragment。当然,为了拟补这个错误,我决定写下这篇博客来展示下Android中Fragment状态缓存和恢复的最佳实践。

理解当Activity状态被缓存或回收时发生了什么
当Activity的onSaveInstanceState 方法被调用时,Activity将自动搜集它所有子View的状态,但是要注意,只有内部实现了状态缓存和恢复接口的View才能被搜集到!(即Activity的子View必须在内部实现状态缓存和恢复的接口) ,随后在onRestoreInstanceState方法被调用的时候,Activity将根据View的id(android:id)来把缓存的数据一对一的传递回去,如下图所示。
这里写图片描述
这里写图片描述
正是因为这个原因,EditText才能在Activity被销毁后重建到时候仍然保持着销毁前的状态,即使我们啥也没干。这不是魔法,这些View能自动的缓存和恢复状态。这也是为什么哪些没有id(android:id)的View就不能缓存和恢复状态的原因。
虽然这些View能自动的缓存状态,但是对于Activity的成员变量来说就行不通了,成员变量会随着Activity的销毁而被回收,所以你必须通过onSaveInstanceState方法和onRestoreInstanceState方法手动地缓存和恢复它们。示例如下:
这里写图片描述

理解当Fragment状态被缓存或回收时发生了什么
当Fragment被系统销毁时,它的表现和Activity是一样一样的。如下图所示:
这里写图片描述
这里写图片描述
这就意味着每一个成员变量也会被销毁掉,所以你必须通过onSaveInstanceState方法和onActivityCreated方法来手动地缓存和恢复状态。同志们要注意啊,Fragment里是没有onRestoreInstanceState方法的,这里和Activity不一样哟~示例如下:
这里写图片描述

对于Fragment来说有些特殊情况是和Activity不一样的,我希望大家能注意下:当Fragment从栈中重新显示的时候,他的View将会被销毁重建!
这里写图片描述
这种情况下要知道,Fragment对象本身并没有被销毁,只是它包含的View会销毁重建。 这种情况下是不会触发缓存状态的。那么当这些重建的View会有什么样的表现呢?其实这不是啥问题,Android早就考虑过这个。这种情况下View内部的状态缓存和恢复接口会被触发,所以只要是实现了这些接口的View都会自动缓存和恢复它自己的状态,例如具有android:freezeText=”true”属性的EditTextTextView,这样它就和销毁前的状态一样了。如下图所示:
这里写图片描述
再次提醒下,这种情况下只有View会销毁重建,Fragment对象本身一直没变,所以它内部的成员变量也不会被销毁,所以你不需要做额外工作。
这里写图片描述

呐,现在你应该明白了,只要是实现了状态缓存和恢复接口的View,在Fragment内部都能自动的进行状态缓存和恢复,而不需要添加额外的工作,那么重点来了,对于Fragment来说,缓存和恢复状态最好的办法就是~~~

应用中所有View都在其内部实现状态缓存和恢复的接口
Android已经提供了给View实现状态缓存和恢复的方法:onSaveInstanceStateonRestoreInstanceState,这是开发者要去实现的任务。
这里写图片描述
总的来说,每一个系统控件,例如EditText, TextView, Checkbox等,它们都已经在内部实现了状态缓存和恢复的接口,在使用这些特性的时候只需要设置一下相关的属性为true即可,例如TextView 设置android:freezeText=”true”
但是,网上众多第三方控件呢,老实讲,很多都没有在内部实现这些接口,导致在实际使用过程中可能带来大麻烦。
如果你决定要使用第三方控件,那么你必须要确认它有在内部实现缓存和恢复状态的接口,否则你需要继承它去写一个子控件来手动实现 onSaveInstanceState/onRestoreInstanceState .示例如下
这里写图片描述
此外,别忘了当你直接继承自View或ViewGroup的时候也要去实现这两个方法,这真的真的真的很重要哟~
还有!别忘了给那些你希望能自动缓存和恢复状态的View添加id!!!
这里写图片描述
到此,我们已经搞定一半的工作了!!!

明确的区分开Fragment的状态和View的状态
为了使你的代码更简洁和更具维护性,你必须区分开Fragment的状态和View的状态。如果一个属性是属于View的,那么在View内部去缓存和恢复它,如果一个属性是属于Fragment的,那么在Fragment内部是缓存和恢复它。(罗里吧嗦的,反正就是不要混淆了View和Fragment的状态嘛) ,示例如下:
这里写图片描述
本帅再次提醒:不要在Fragment的onSaveInstanceState方法里缓存View的状态,反之亦然。

好了,这就是Activity/Fragment 状态缓存和恢复的最佳实践,希望能对你有帮助。

0 0
原创粉丝点击