如果你是一个有经验的 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);
}

解放你的双手

上面的方案当然是正确的。但是并不优雅,为了保持变量的值,引入了两个方法 ( onSaveInstanceStateonRestoreInstanceState ) 和两个常量 ( 为了存储两个变量而定义的两个常量,仅仅为了放到 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}"
}
}

然后,在 applicationlibrary 模块的 build.gradle 文件中应用插件:

apply plugin: 'com.android.application'
// apply plugin: 'com.android.library'
apply plugin: 'save.state'

万事具备!再也不需要写烦人的回调,因为你的时间非常值钱!做了一点微小的工作,如果我帮你节省下来了喝一杯咖啡的时间,希望你可以帮我点一个 Star,谢谢

不需要再手写 onSaveInstanceState 了,因为你的时间非常值钱的更多相关文章

  1. 手写 Vue 系列 之 Vue1.x

    前言 前面我们用 12 篇文章详细讲解了 Vue2 的框架源码.接下来我们就开始手写 Vue 系列,写一个自己的 Vue 框架,用最简单的代码实现 Vue 的核心功能,进一步理解 Vue 核心原理. ...

  2. 一套手写ajax加一般处理程序的增删查改

    倾述下感受:8天16次驳回.这个惨不忍睹. 好了不说了,说多了都是泪. 直接上代码 : 这个里面的字段我是用动软生成的,感觉自己手写哪些字段太浪费时间了,说多了都是泪 ajax.model层的代码: ...

  3. 手写MVC框架(一)-再出发

    背景 前段时间把之前写的DAO框架(手写DAO框架(一)-从“1”开始)整理了一下,重构了一版.整理过程中看以前写的代码,只是为了了解实现,只是为了实现,代码写的有点粗糙.既然已经整理了DAO框架,索 ...

  4. Android 手写Binder 教你理解android中的进程间通信

    关于Binder,我就不解释的太多了,网上一搜资料一堆,但是估计还是很多人理解的有困难.今天就教你如何从 app层面来理解好Binder. 其实就从我们普通app开发者的角度来看,仅仅对于androi ...

  5. 【Xamarin挖墙脚系列:代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧(转)】

    正愁如何选择构建项目中的视图呢,现在官方推荐画板 Storybord...但是好像 xib貌似更胜一筹.以前的老棒子总喜欢装吊,用代码写....用代码堆一个HTML页面不知道你们尝试过没有.等页面做出 ...

  6. .netER的未来路,关于基础是否重要和应该自己手写代码吗?

    http://www.cnblogs.com/onepiece_wang/p/5558341.html#!comments 引用"基础知识的学习,一开始可能是背书,但是在后续若干年的工作过程 ...

  7. 关于代码手写UI,xib和StoryBoard

    代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用.Geek们喜欢用代码构建UI,是因为代码是键盘敲出来的,这样可以做到不开IB,手不离开键盘就完成工作,可以专注于编码环境, ...

  8. 手写@koa/router源码

    上一篇文章我们讲了Koa的基本架构,可以看到Koa的基本架构只有中间件内核,并没有其他功能,路由功能也没有.要实现路由功能我们必须引入第三方中间件,本文要讲的路由中间件是@koa/router,这个中 ...

  9. 手写koa-static源码,深入理解静态服务器原理

    这篇文章继续前面的Koa源码系列,这个系列已经有两篇文章了: 第一篇讲解了Koa的核心架构和源码:手写Koa.js源码 第二篇讲解了@koa/router的架构和源码:手写@koa/router源码 ...

随机推荐

  1. C# 在窗体上可拖动控件

    最近做了一个标签打印配置功能,需要根据客户需求自定义标签格式.显示内容,这时就用到了后台生成控件,并且其控件可在窗口中进行拖动,这里仅为记录一下实现过程,方便以后使用. 结果图: 源码: using ...

  2. IdentityServer Resource Owner Password

    Resource Owner Password 模式需要自己实现用户名密码的校验 新增ResourceOwnerPasswordValidator实现IResourceOwnerPasswordVal ...

  3. C++版 - 剑指offer 面试题4: 替换空格 题解

    面试题4:替换空格 提交网址: http://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=1 ...

  4. MaskRCNN-Keypoints

    这个月先写一篇吧,后面要复习数学考试了,可能到时候就忘了.今天写一个比较有意思的东西,关于人体的分割与姿态估计.如下图所示: 图片选自mask rcnn的论文,这里由于时间的关系,就不多叙述技术细节了 ...

  5. ES6躬行记(11)——对象

    在第5篇中,讲解了多个对象字面量的改进,本节将重点介绍两个新增的静态方法,以及对象属性的重复处理和枚举顺序. 一.Object.is() 此方法用于判断两个值是否相同,内部实现了SameValue算法 ...

  6. DRDS SQL 审计与分析——全面洞察 SQL 之利器

    背景 数据库存储着系统的核心数据,其安全方面的问题在传统环境中已经成为泄漏和被篡改的重要根源.而在云端,数据库所面临的威胁被进一步的放大.因此,对云数据库的操作行为尤其是全量 SQL 执行记录的审计日 ...

  7. 最好用的编辑器之一:Vim-Go环境搭建

    本文由Librant发表 如果说在Linux环境下,什么编辑器最好用,如果我说是VIM,估计会有一大部分人嗤之以鼻,怎么可能.VIM可能是他用过众多编辑器最难用的一个.在我司用的是云虚拟机,说实话吧, ...

  8. Elasticsearch 学习总结 - 相关配置补充说明

    一.   Elasticsearch的基本概念 term索引词,在elasticsearch中索引词(term)是一个能够被索引的精确值.foo,Foo Foo几个单词是不相同的索引词.索引词(ter ...

  9. OpenResty api网关设计

    本文讲述 OpenResty api网关设计,主要涉及api网关介绍.openresty api网关 请求路由(路由判断.路由重写.服务判断.限流).授权验证(统一认证).动态Upstream 以及这 ...

  10. Spring基础系列-AOP源码分析

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...