不需要再手写 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";// ...@Overridepublic 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 方法里把原来保存的值重新取出来:

@Overrideprotected 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,谢谢 :)

SaveState Github 地址:https://github.com/PrototypeZ/SaveState

原文发布于微信公众号 - Android群英传(android_heroes)

原文发表时间:2018-06-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android开发指南

2.抽取代码(BaseActivity)

3578
来自专栏everhad

[异常特工]android常见bug跟踪

前言 对app的线上bug的收集(友盟、云捕等)有时会得到这样的异常堆栈信息:没有一行代码是有关自身程序代码的。这使得对bug的解决无从下手,根据经验,内存不足...

2035
来自专栏Android中高级开发

Android开发之漫漫长途 Fragment番外篇——TabLayout+ViewPager+Fragment

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

2041
来自专栏积累沉淀

多人聊天室

最近学完网络线程协议 ,因此写了一个用java编写的聊天室 话不多说 效果如图 ? 首先 创建服务器端 package com.yc.server...

7018
来自专栏函数式编程语言及工具

Akka(31): Http:High-Level-Api,Route rejection handling

   Route 是Akka-http routing DSL的核心部分,使用户能比较方便的从http-server的角度筛选http-request、进行se...

2467
来自专栏王磊的博客

react-native绑定优酷SDK-附效果图和源码

ReactNative绑定优酷SDK需要用到两部分知识: 优酷本身的sdk绑定; RN与原生界面的交互; 效果: ? RN版本:0.49.3 代码更新日期:20...

3886
来自专栏猿份到

浅谈Retrofit 源码

现在的项目界面都是按iOS的风格,虽然界面无法发挥出我们大Android的风格,网络框架动不动就是mvp+ okhttp +retrofit+rxjava,m...

3618
来自专栏何俊林

Android Multimedia框架总结(二十三)MediaCodec补充及MediaMuxer引入(附案例)

前言:前面几章都是分析MediaCodec相关源码,有收到提问,说MediaCodec到底是硬解码还是软解码?看下今天的Agenda: MediaCodec到...

32010
来自专栏酷玩时刻

Retrofit2+Rxjava+MVP 实践

此博文根据前面两篇文章 Android MVP 架构初试 Android MVP 架构封装 再结合主流框架Retrofit2+Rxjava来个实践(实现聚合网...

3024
来自专栏向治洪

仿淘宝收货地址,本地数据库

谁说咱们攻城狮不能写出既幽默又能懂的博客呢,本人想推出一系列博文,可以给刚接触Android开发的做一个参考,也可以与接触Android已久的各路大神比较一下,...

1.3K7

扫码关注云+社区

领取腾讯云代金券