不要在Android的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);
使用官方推荐的方法中的一种将数据持久化,存储在磁盘中;
在使用数据和句柄的时候做空值检测;
不要在Android的Application对象中缓存数据!的更多相关文章
- 为什么不能往Android的Application对象里存储数据
在一个App里面总有一些数据需要在多个地方用到.这些数据可能是一个 session token,一次费时计算的结果等.通常为了避免activity之间传递对象的开销 ,这些数据一般都会保存到持久化存储 ...
- 【安卓开发】为什么不能往Android的Application对象里存储数据
在一个App里面总有一些数据需要在多个地方用到.这些数据可能是一个 session token,一次费时计算的结果等.通常为了避免activity之间传递对象的开销 ,这些数据一般都会保存到持久化存储 ...
- 不要在Application中缓存数据
在你的App中的很多地方都需要使用到数据信息,它可能是一个session token,一次费时计算的结果等等,通常为了避免Activity之间传递数据的开销,会将这些数据通过持久化来存储. 有人建 ...
- Android 利用Application对象存取公共数据
本文章来给大家介绍Android 利用Application对象存取公共数据. Android系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量. ...
- Application对象的使用-数据传递以及内存泄漏
Application的使用 What is Application Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创 ...
- .NET中利用反射来实现自动映射两个对象中的数据成员
在以前的项目开发之中,经常会遇到这样一个问题:比如在外面项目的架构设计之中,我们采用MVC和EntityFramework来构建一个Web应用程序.比如我们采用常用的多层架构,例如有Presentat ...
- Android 向Application对象添加Activity监听
可以建立对象把Application.ActivityLifecycleCallbacks接口中的函数实现,并利用public void registerActivityLifecycleCallba ...
- Android - 读取XML文件中的数据
读取XML中存储的数据.将xmlfile.xml存放在assets文件夹中.在activity_main.xml中创建一个textview,用来显示读取到的数据. XML文件内容如下:xmlfile. ...
- angularJs中缓存数据,免去重复发起请求的几种写法
带缓存处理的两种写法 过程:点击button触发load()方法,请求数据成后显示到页面中.如果已经请求过则从缓存中读取. 在线浏览 写法1: function demo(){ if (demo.ca ...
随机推荐
- 控制流之if
if语句if语句用来检验一个条件, 如果 条件为真,我们运行一块语句(称为 if-块 ), 否则 我们处理另外一块语句(称为 else-块 ). else 从句是可选的. ~~~~~~~~~~~~~~ ...
- Laravel 数据插入
Laravel 的数据库操作基于 Eloquent ORM,在插入数据时有以下几种方式,返回结果也不会不同: 1.insert 插入后会返回 true or false: 2.create 插入成功后 ...
- (中等) POJ 1703 Find them, Catch them,带权并查集。
Description The police office in Tadu City decides to say ends to the chaos, as launch actions to ro ...
- Cookie的格式及组成
转自:http://blog.csdn.net/talking12391239/article/details/9665185 Cookie由变量名和值组成,类似JavaScript变量.其属性里既有 ...
- Docker 命令(二)
Docker 入门 启动docker systemctl start docker 帮助命令 docker --help docker [Commands] --help 例:docker run ...
- Python学习【第十二篇】模块(2)
序列化 1.什么是python序列化? 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling 序列化就是将python的数据类型转换成字符串 反序列化就是将字符串转换成 ...
- java实现——004替换空格
1.创建新的字符串 public class T004 { public static void main(String[] args){ System.out.println(replaceBlan ...
- Zend Framework Module之多模块配置
摘要:该文将为大家简单介绍一下如何使用zend framework创建模块化的应用程序. zend framework对多模块的支持是很好的,但是可能是由于功能太过强大的缘故,部署起来并不是很容易.许 ...
- UVa 459 - Graph Connectivity
题目大意:给你一个无向图的顶点和边集,让你求图中连通分量的个数.使用并查集解决. #include <cstdio> #include <cstring> #define MA ...
- Beautifulsoup 和selenium 的查询
Selenium There are vaious strategies to locate elements in a page. You can use the most appropriate ...