不要在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 ...
随机推荐
- MySQL 5.5.x配置文件详解
MySQL 5.5.x my.cnf参数配置优化详解 一直有耳闻MySQL5.5的性能非常NB,所以近期打算测试一下,方便的时候就把bbs.kaoyan.com升级到这个版本的数据库.今天正好看到一篇 ...
- shell字符串操作之cut---实现字符串截取
shell中(字符串截取) cut是以每一行为一个处理对象的,这种机制和sed是一样的.(关于sed的入门文章将在近期发布) 2 cut一般以什么为依据呢? 也就是说,我怎么告诉cut我想定位到的剪切 ...
- print打印网页相关
作者:zccst 1,CSS <link href="/style/print.css" rel="stylesheet" type="text ...
- iOS开发实现Label中多颜色多字体
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(8, 100, 300, 30)]; label.textColor = wor ...
- 【转】C/CPP之static
静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见.用法1:函数内部声明 ...
- Memcached源码分析之slabs.c
#include "memcached.h" #include <sys/stat.h> #include <sys/socket.h> #include ...
- 处理Block中的self问题(Capturing 'self' strongly in this block is likely to lead to a retain cycle)
警告:ARC Retain Cycle Capturing 'self' strongly in this block is likely to lead to a retain cycle 代码: ...
- 安卓 canvas
[转]http://blog.sina.com.cn/s/blog_61ef49250100qw9x.html(easy) [转]http://blog.csdn.net/rhljiayou/arti ...
- 基于RBAC的权限设计模型
个部件模型组成,这4个部件模型分别是基本模型RBAC0(Core RBAC).角色分级模型RBAC1(Hierarchal RBAC).角色限制模型RBAC2(Constraint RBAC)和统一模 ...
- 后端数据库使用 Bomb方案
不再需要阿里云进行部署: http://docs.bmob.cn/ios/faststart/index.html?menukey=fast_start&key=start_ios