Android 一个轻量级的自动恢复内存数据框架
来源:互联网 发布:软件如何授权 编辑:程序博客网 时间:2024/06/06 04:52
引入
android 内存被回收是一个开发者的常见问题。当我们跳转到一个二级界面,或者切换到后台的时候,如果时间过长或者手机的内存不足,当我们再返回这个界面的时候,activity或fragment就会被内存回收。这时候虽然界面被重新执行了onCreate,但是很多变量的值却已经被置空,这样就导致了很多潜在的bug,已经很多空指针的问题。
其实这种问题需要解决的话也很简单。大家知道,当Activity或者Fragment被内存回收后,我们再进入这个界面,它会自动重新进行onCreate操作,并且系统会帮助我们保存一些值。但是系统只会保存界面上的一些元素,比如textview中的文字,但是很多全局变量仍然会被置空。
对于保存这些变量,我们可以重写onSaveInstanceState这个方法,在onCreate中即可恢复数据。代码如下:
|
public int a;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); //内存回收,界面重新onCreate后,恢复数据 if(savedInstanceState != null){ a = savedInstanceState.getInt("A"); }}private void initData() { ...}@Overrideprotected void onSaveInstanceState(Bundle outState) { //保存数据 outState.putInt("A", a); super.onSaveInstanceState(outState);}
通过这样的操作,便可以解决内存回收后变量a的值变为初始值0的问题。
问题到这里,似乎已经可以解决内存被回收的问题了。但是随着项目的开发,一个Activity中的变量以及代码会变得非常多,这时候我们需要去保存某个值就会使代码变得越来越凌乱,同时不断重复的去写outState.putXX已经savedInstanceState.getXX这样的代码都是很重复的,一不小心还会去写错中间的key值。
于是我写了这个很轻量级的框架,来解决这个问题。先给出引入这个框架后的代码写法:
@NeedSavepublic String test;@NeedSaveprivate boolean b;@NeedSavepublic Boolean c;@NeedSavepublic ArrayList<String> t;@NeedSavepublic Integer i;@NeedSave(isParcelable = true)public ParcelableObject example;@NeedSavepublic SerializableObject example;@NeedSavepublic Float f1;@NeedSavepublic float f2;@NeedSavepublic char achar;@NeedSavepublic char achars[];@NeedSavepublic int sssss[];@NeedSavepublic Bundle bundle;@NeedSavepublic int a;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); SaveHelper.bind(this,savedInstanceState);}private void initData() { ...}@Overrideprotected void onSaveInstanceState(Bundle outState) { SaveHelper.save(this,outState); super.onSaveInstanceState(outState);}
这里我特地写了很多的变量,但是无论这个Activity中有多少变量,我在onCreate和onSaveInstanceState代码中都只要去各写一行代码,同时给变量加一个标签标记一个即可:
@NeedSave SaveHelper.bind(this,savedInstanceState); SaveHelper.save(this,outState);
这样就不会因为这种太多的重复的操作去导致代码逻辑的混乱,同时也避免了敲代码时因为key写错导致的错误。
效果展示
我们来看一下测试代码:
不进行数据保存操作
很简单,就是通过点击事情,去给变量“testString”赋值,然后再去模拟内存被回收的情况,看一下显示的值是否是内存被回收前的。
调用框架代码后的内存恢复
加入框架代码:
加入代码之后的效果:
原理介绍
@NeedSave
这是一个注解,这个注解只能使用在全局变量中,特别注意,被加上这个注解的变量必须是public,否则会不生效。
当前支持保存的类型有:
String boolean Boolean ArrayList int int[] Integer Parcelable Serializable float Float char[] char Bundle 注意,如果是Parcelable类型,需要特别在注解中加入 @NeedSave(isParcelable = true) 这样标记
SaveHelper.bind(this,savedInstanceState);
这个方法其实是恢复数据的时候去调用的。
public static <T> void bind(T recover, Bundle savedInstanceState){ if(savedInstanceState != null){ ISaveInstanceStateHelper<T> saveInstanceStateHelper = findSaveHelper(recover); if(saveInstanceStateHelper != null){ saveInstanceStateHelper.recover(savedInstanceState, recover); } }}
savedInstanceState不会null的时候,说明就是需要内存恢复的时候,这时候就会去通过findSaveHelper方法找到一个实现类,然后去调用recover方法恢复数据。
SaveHelper.save(this,outState);
这是一个保存数据的方法,注意的是,这个方法必须在super.onSaveInstanceState(outState);之前调用。
public static <T> void save(T save, Bundle outState){ ISaveInstanceStateHelper<T> saveInstanceStateHelper = findSaveHelper(save); if(saveInstanceStateHelper != null){ saveInstanceStateHelper.save(outState, save); } }
它最终调用的是ISaveInstanceStateHelper实现类的save方法。
ISaveInstanceStateHelper实现类
这个类是一个接口,专门用来保存和恢复数据用。这个类是不要我们自己写的,在代码编译的时候会自动生成模板代码。整个调用过程中也只有寻找ISaveInstanceStateHelper实现类的findSaveHelper这个方法调用了反射,其他时候不会去用到反射,而影响效率。
自动生成代码所在位置:
自动生成的代码如下:
public class MainActivity_SaveStateHelper implements ISaveInstanceStateHelper<MainActivity> { @Override public void save(Bundle outState, MainActivity save) { outState.putString("TEST",save.test); outState.putBoolean("C",save.c); outState.putSerializable("T",save.t); outState.putInt("I",save.i); outState.putParcelable("EXAMPLE",save.example); outState.putFloat("F1",save.f1); outState.putFloat("F2",save.f2); outState.putChar("ACHAR",save.achar); outState.putCharArray("ACHARS",save.achars); outState.putIntArray("SSSSS",save.sssss); outState.putIntArray("SASA",save.sasa); outState.putBundle("BUNDLE",save.bundle); outState.putInt("A",save.a); } @Override public void recover(Bundle savedInstanceState, MainActivity recover) { if(savedInstanceState != null) { recover.test = savedInstanceState.getString("TEST"); recover.c = savedInstanceState.getBoolean("C"); recover.t = (ArrayList<String>)savedInstanceState.getSerializable("T"); recover.i = savedInstanceState.getInt("I"); recover.example = savedInstanceState.getParcelable("EXAMPLE"); recover.f1 = savedInstanceState.getFloat("F1"); recover.f2 = savedInstanceState.getFloat("F2"); recover.achar = savedInstanceState.getChar("ACHAR"); recover.achars = savedInstanceState.getCharArray("ACHARS"); recover.sssss = savedInstanceState.getIntArray("SSSSS"); recover.sasa = savedInstanceState.getIntArray("SASA"); recover.bundle = savedInstanceState.getBundle("BUNDLE"); recover.a = savedInstanceState.getInt("A"); } }}
总结
看到这里大家已经猜到其实这个框架的实现原理和BufferKnife是相同的。而bufferknife的原理很多文章都有,这里就不过多介绍了。
github地址:https://github.com/JavaNoober/AutoSave
引入方式,在app的gradle中加入下面依赖即可:
compile 'com.noober:savehelper:1.0.0'compile 'com.noober:savehelper-api:1.0.0'annotationProcessor 'com.noober:processor:1.0.0'
- Android 一个轻量级的自动恢复内存数据框架
- 一个可以自动调用OnSaveInstanceState保存并恢复数据的框架
- 一个轻量级的分页框架
- 自己动手写一个轻量级的Android网络请求框架
- 自己动手写一个轻量级的Android网络请求框架
- 打造一个轻量级,简单,易用的Android Banner框架
- 使用CoreData的轻量级自动数据迁移
- 使用CoreData的轻量级自动数据迁移
- 一个超轻量级的 ORM 框架
- 一个轻量级的分布式RPC框架
- ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架
- android 超轻量级的ORM框架
- XDroid 轻量级的Android快速开发框架
- 继文章‘’ 自己动手写一个轻量级的Android网络请求框架‘’后续------增加缓存功能
- 继文章‘’ 自己动手写一个轻量级的Android网络请求框架‘’补充------增加进度回调
- android轻量级缓存框架ASimpleCache的使用 (网络请求数据并缓存)
- android轻量级缓存框架ASimpleCache的使用 (网络请求数据并缓存)
- 一个轻量级的JS框架 Liger UI框架
- Unity调用Android方法
- Dexie学习
- 使用truss、strace或ltrace诊断软件的"疑难杂症"
- python解析域名
- Git 开发规范流程
- Android 一个轻量级的自动恢复内存数据框架
- springMvc Jsp下拉框(select)级联
- Echarts怎么获取json数据
- PostgreSQL配置文件--QUERY TUNING
- 使用UDP协议编写一个网络程序,设置接收端程序的监听端口是8001,发送端发送的数据是“Hello, world”。
- 某软件破解实验过程(记录)
- 高精压位
- vue中实现先请求数据再渲染dom
- cent0S 7 安装 cdh5.13 笔记之四: 配置 hadoop