不要在Application中缓存数据
在你的App中的很多地方都需要使用到数据信息,它可能是一个session token,一次费时计算的结果等等,通常为了避免Activity之间传递数据的开销,会将这些数据通过持久化来存储。
有人建议将这些数据放在Application对象中方便所有的Activity访问,这个解决方案简单、优雅并且是……完全错误的。
你如果你将数据缓存到Application对象中,那么有可能你的程序最终会由于一个NullPointerException异常而崩溃掉。
一个简单的测试程序
这是自定义Application的代码:
// access modifiers omitted for brevity
class MyApplication extends Application { String name; String getName() {
return name;
} void setName(String name) {
this.name = name;
}
}
在第一个Activity中,我们将用户信息存储在Application对象中:
// access modifiers omitted for brevity
class WhatIsYourNameActivity extends Activity { void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.writing); // Just assume that in the real app we would really ask it!
MyApplication app = (MyApplication) getApplication();
app.setName("Developer Phil");
startActivity(new Intent(this, GreetLoudlyActivity.class)); } }
然后在第二个Activity中通过Application获取存储的用户信息:
// access modifiers omitted for brevity
class GreetLoudlyActivity extends Activity { TextView textview; void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.reading);
textview = (TextView) findViewById(R.id.message);
} void onResume() {
super.onResume(); MyApplication app = (MyApplication) getApplication();
textview.setText("HELLO " + app.getName().toUpperCase());
}
}
测试步骤
打开这个APP;
在WhatIsYourNameActivity中,你按要求输入用户名并将其缓存到MyApplication这个对象中;
接着在GreetLoudlyActivity中,程序从MyApplication对象中取出用户名并显示出来;
用户按了Home按键离开了该APP;
数小时之后,系统由于内存不足(用户在体验其它APP呢,前台的任务总是优先的嘛)会在后台将你的程序杀掉;在你重新启动该APP之前一切看上去很好,但是…..;
用户重新打开了这个APP;
Android会重新创建一个之前被Kill掉的MyApplication实例并恢复GreetLoudlyActivity;
GreetLoudlyActivity去获取用户名时,会因为获取的为空值报NullPointerException而崩溃掉。
为什么会这样?
在上面这个例子中,程序之所以会崩溃掉是因为恢复之后APP的Application对象是全新的,所以缓存在Application中的用户名成员变量为空值,在程序调用String的toUpperCase()方法时由于NullPointerException而崩溃掉。
导致这个问题的主要原因是:Application对象并不是始终在内存中的,它有可能会由于系统内存不足而被杀掉。但Android在你恢复这个应用时并不是重新开始启动这个应用,它会创建一个新的Application对象并且启动上次用户离开时的activity以造成这个app从来没有被kill掉得假象。
我们以为可以通过Application来缓存数据,却没想到恢复APP时直接跑了B Activity而不是先启动A Activity,最终导致的结果是程序意外的崩溃掉了。
有哪些替代方法可用呢?
对于数据缓存问题我也没有比较好的办法,但你可以按照下面其中一种方式来处理:
通过Intent在Activity之间来传递数据(但是请别传递大量数据,这有可能导致程序异常或者ANR);
使用官方推荐的方法中的一种将数据持久化,存储在磁盘中;
在使用数据和句柄的时候做空值检测;
如何模拟应用程序被杀掉?
更新:Daniel Lew指出,最简单的方法是在DDMS中点击”Stop Porcess”杀掉你的程序,在你调试程序的时候可以这样做。
你可以通过模拟器或者一个Root过的真机来测试实际效果:
按Home按键退出你的程序;
在控制台,敲入如下命令(Windows系统下 WIN + R -> cmd -> 回车)
# 找到该APP的进程ID
adb shell ps
# 找到你APP的报名 # Mac/Unix: save some time by using grep:
adb shell ps | grep your.app.package # 按照上述命令操作后,看起来是这样子的:
# USER PID PPID VSIZE RSS WCHAN PC NAME
# u0_a198 21997 160 827940 22064 ffffffff 00000000 S your.app.package # 通过PID将你的APP杀掉
adb shell kill -9 21997 # APP现在被杀掉啦
现在在桌面长按Home按键通过后台任务管理器打开你的APP,此时系统就会重新创建一个MyApplication实例了。
总结
不要在Application对象中缓存数据化,这有可能会导致你的程序崩掉。请使用Intent在各组件之间传递数据,抑或是将数据存储在磁盘中,然后在需要的时候取出来。
并不仅仅只有Application对象是这样的,其它的单例或者公有静态类也有可能会由于系统内存而被杀掉,谨记。
不要在Application中缓存数据的更多相关文章
- 不要在Android的Application对象中缓存数据!
前言 在你的App中的很多地方都需要使用到数据信息,它可能是一个session token,一次费时计算的结果等等,通常为了避免Activity之间传递数据的开销,会将这些数据通过持久化来存储. ...
- 配置监听器 服务器启动时 检索常用数据 保存在application中 减少数据的查询操作(OA项目)
模型 大致介绍一下:左侧菜单是用户登录成功之后显示的页面 这些数据就是通过查询数据库 然后在页面中把查到的数据 循环遍历出来 构成了操作菜单 第一个解决的问题:常用数据 在服务器启动的时候 ...
- angularJs中缓存数据,免去重复发起请求的几种写法
带缓存处理的两种写法 过程:点击button触发load()方法,请求数据成后显示到页面中.如果已经请求过则从缓存中读取. 在线浏览 写法1: function demo(){ if (demo.ca ...
- 使用 ObjectDataSource 缓存数据
简介 就计算机科学而言 , 缓存 过程包括成本昂贵的数据或信息的获取 , 以及将备份存储在可快速访问的位置.对于数据驱动的应用程序,大型.复杂的查询通常会消耗大量应用程序执行时间.要提升这类应用程序的 ...
- 在Spring Boot中使用数据缓存
春节就要到了,在回家之前要赶快把今年欠下的技术债还清.so,今天继续.Spring Boot前面已经预热了n篇博客了,今天我们来继续看如何在Spring Boot中解决数据缓存问题.本篇博客是以初识在 ...
- Application中数据传递及内存泄漏问题
原文地址:http://android.tgbus.com/Android/tutorial/201107/359474.shtml Application的使用 Application和Actovo ...
- 在Activity和Application中使用SharedPreferences存储数据
1.在Activity中创建SharedPreferences对象及操作方法 SharedPreferences pre=getSharedPreferences("User", ...
- LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对
回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里. LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL ...
- EF封装类 增加版,增加从缓存中查找数据方法,供参考!
EF封装类 增加版,增加从缓存中查找数据方法,供参考! 这个类是抽象类,我这里增加了需要子类验证的方法ValidateEntity,方便扩展,若想直接使用该类,可以将该类更改成静态类,里面所有的方法都 ...
随机推荐
- EXCEL数据导入数据库的另一种方式
一.直接代码 var fileResult = openFileDialog1.ShowDialog(); if (fileResult == System.Windows.Forms.DialogR ...
- debug---null Pointer Exception--一步步查找(2)
添加PartyLocationRepository后,再次在Ubuntu中编译项目,再次报空指针异常. 直接在createDto处打断点,然后debug每个表达式的值,找出来到底是哪个为null. 经 ...
- 形式化验证工具(PAT)Reader-Writers Problem学习
经过前几次的学习,我们应该对PAT有一点点的了解了,我们加下来就直接看例子中的一个问题,这个问题比较简单. 看代码: //The classic Readers/Writers Example mod ...
- 2019年第十届蓝桥杯省赛总结(JavaA组)
//update3.28:省一rank4,莫名进了国赛好神奇.. 记yzm10第一次体验A组(纯粹瞎水). 早闻山东的JavaA组神仙打架,进国赛都成了奢望(往年只有五个名额),因此抱着做分母的心态来 ...
- UWP&WP8.1 中文网页字符乱码 字符乱码 UTF-8转GBK 解决方法
UWP 方法 async void Download() { /*新建HttpClient*/ HttpClient web_ = new HttpClient(); /*使用HttpClient的G ...
- 网易CentOS yum源
wget http://mirrors.163.com/.help/CentOS6-Base-163.repo
- [hdu 2604] Queuing 递推 矩阵快速幂
Problem Description Queues and Priority Queues are data structures which are known to most computer ...
- slice()、substring()、substr()的区别用法
在js中字符截取函数有常用的三个slice().substring().substr()了,下面我来给大家介绍slice().substring().substr()函数在字符截取时的一些用法与区别吧 ...
- ASP.NET-GridView之导出excel或word
在CS阶段我们涉及到表格的导出,再Web开发同样可以实现,而且实现形式多种多样.以下面的例子说明表格导出到excel和word 这里用到了一个后台方法输出流形成***文件的的公共方法 DEMO < ...
- bzoj 1013: [JSOI2008]球形空间产生器sphere【高斯消元】
n+1个坐标可以列出n个方程,以二维为例,设圆心为(x,y),给出三个点分别是(a1,b1),(a2,b2),(a3,b3) 因为圆上各点到圆心的距离相同,于是可以列出距离方程 \[ (a1-x)^2 ...