不需要再手写 onSaveInstanceState 了,因为你的时间非常值钱
如果你是一个有经验的 android 程序员,那么你肯定手写过许多 onsaveinstancestate
以及 onrestoreinstancestate
方法用来保持 activity 的状态,因为 activity 在变为不可见以后,系统随时可能把它回收用来释放内存。重写 activity 中的 onsaveinstancestate
方法 是 google 推荐的用来保持 activity 状态的做法。
google 推荐的最佳实践
onsaveinstancestate
方法会提供给我们一个 bundle
对象用来保存我们想保存的值,但是 bundle
存储是基于 key - value 这样一个形式,所以我们需要定义一些额外的 string
类型的 key 常量,最后我们的项目中会充斥着这样代码:
static final string state_score = "playerscore"; static final string state_level = "playerlevel"; // ... @override public void onsaveinstancestate(bundle savedinstancestate) { // save the user's current game state savedinstancestate.putint(state_score, mcurrentscore); savedinstancestate.putint(state_level, mcurrentlevel); // always call the superclass so it can save the view hierarchy state super.onsaveinstancestate(savedinstancestate); }
保存完状态之后,为了能在系统重新实例化这个 activity 的时候恢复先前被系统杀死前的状态,我们在 oncreate
方法里把原来保存的值重新取出来:
@override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); // always call the superclass first // check whether we're recreating a previously destroyed instance if (savedinstancestate != null) { // restore value of members from saved state mcurrentscore = savedinstancestate.getint(state_score); mcurrentlevel = savedinstancestate.getint(state_level); } else { // probably initialize members with default values for a new instance } // ... }
当然,恢复这个操作也可以在 onrestoreinstancestate
这个方法实现:
public void onrestoreinstancestate(bundle savedinstancestate) { // always call the superclass so it can restore the view hierarchy super.onrestoreinstancestate(savedinstancestate); // restore state members from saved instance mcurrentscore = savedinstancestate.getint(state_score); mcurrentlevel = savedinstancestate.getint(state_level); }
解放你的双手
上面的方案当然是正确的。但是并不优雅,为了保持变量的值,引入了两个方法 ( onsaveinstancestate
和 onrestoreinstancestate
) 和两个常量 ( 为了存储两个变量而定义的两个常量,仅仅为了放到 bundle
里面)。
为了更好地解决这个问题,我写了 savestate 这个插件:
在使用了 savestate 这个插件以后,保持 activity 的状态的写法如下:
public class myactivity extends activity { @autorestore int myint; @autorestore ibinder myrpccall; @autorestore string result; @override protected void oncreate(bundle savedinstancestate) { // your code here } }
没错,你只需要在需要保持的变量上标记 @autorestore
注解即可,无需去管那几个烦人的 activity 回调,也不需要定义多余的 string
类型 key 常量。
那么,除了 activity 以外,fragment 能自动保持状态吗?答案是: yes!
public class myfragment extends fragment { @autorestore user currentloginuser; @autorestore list<map<string, object>> networkresponse; @nullable @override public view oncreateview(@nonnull layoutinflater inflater, @nullable viewgroup container, @nullable bundle savedinstancestate) { // your code here } }
使用方法和 activity 一模一样!不止如此,使用场景还可以推广到 view
, 从此,你的自定义 view,也可以把状态保持这个任务交给 savestate :
public class myview extends view { @autorestore string sometext; @autorestore size size; @autorestore float[] myfloatarray; public mainview(context context) { super(context); } public mainview(context context, @nullable attributeset attrs) { super(context, attrs); } public mainview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); } }
现在就使用 savestate
引入 savestate 的方法也十分简单:
首先,在项目根目录的 build.gradle
文件中增加以下内容:
buildscript { repositories { google() jcenter() } dependencies { // your other dependencies // dependency for save-state classpath "io.github.prototypez:save-state:${latest_version}" } }
然后,在 application 和 library 模块的 build.gradle
文件中应用插件:
apply plugin: 'com.android.application' // apply plugin: 'com.android.library' apply plugin: 'save.state'
万事具备!再也不需要写烦人的回调,因为你的时间非常值钱!做了一点微小的工作,如果我帮你节省下来了喝一杯咖啡的时间,希望你可以帮我点一个 star,谢谢 :)
savestate github 地址:https://github.com/prototypez/savestate
上一篇: 一百多行python代码实现抢票助手