如果你是一个有经验的 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. 纯手写SpringMVC框架,用注解实现springmvc过程

    闲话不多说,直接上代码! 1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping ...

  2. sql server 备份与恢复系列二 事务日志概述

    1.1  日志文件与数据文件一致性 在上一章备份与恢复里了解到事务日志的重要性,这篇重点来了解事务日志. 事务日志记录了数据库所有的改变,能恢复该数据库到改变之前的任意状态.在sql server实例 ...

  3. centos 7 linux系统默认ftp安装配置和部署(详细讲解)

    小生接触 Linux 系统时间不长,想解决linux系统ftp安装及部署问题,折腾了大半天,终于弄出来了,将各路高手的配置方法综合了一下,如有不对之处,欢迎各位看客指正,感谢! 一.声明: 本文采用操 ...

  4. 【干货】Jquery.Datables与Bootstrap3的组合使用

    官方地址 datatables官方网址:www.datatables.net 下载bootstrap3与datables文件包 引用文件 css:bootstrap.css.dataTables.bo ...

  5. mongo-spark-读取不同的库数据和写入不同的库中

    mongo-spark-读取不同的库数据和写入不同的库中 package com.example.app import com.mongodb.spark.config.{ReadConfig, Wr ...

  6. Mybatis源码解析-MapperRegistry代理注册mapper接口

    知识储备 SqlsessionFactory-mybatis持久层操作数据的前提,具体的解析是通过SqlSessionFactoryBean生成的,可见>>>Spring mybat ...

  7. 开发-封闭原则(OCP)

    1.什么是“开放-封闭” 随着软件系统规模的不断增大,软件系统的维护和修改的复杂性不断提高,这种困境促使法国工程院士Bertrand Meyer在1998年提出了“开放-封闭”(Open-Close ...

  8. 2.ES6引进的新特性——类Class

    为什么? ES6中引入了类,类在java/c++等面向对象的编程语言常见,JS引入类是为了在日后使用js开发大型的应用程序,类本质是语法糖(语法上更加人性化) 以前写一个类 function User ...

  9. python等值和大小比较

    等值.大小比较 在python中,只要两个对象的类型相同,且它们是内置类型(字典除外),那么这两个对象就能进行比较.关键词:内置类型.同类型.所以,两个对象如果类型不同,就没法比较,比如数值类型的数值 ...

  10. React Fiber源码分析 第二篇(同步模式)

    先附上两张流程图 1.scheduleRootUpdate  这个函数主要执行了两个操作  1个是创建更新createUpdate并放到更新队列enqueueUpdate, 1个是执行sheculeW ...