不要在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 ...
随机推荐
- 布隆过滤器(BoomFilter)
1.原理: a.解决的问题: 判断一个元素是否在一个集合中 b.Hash表的特点: i.快速准确 ...
- POJ 3362 Protecting the Flowers
这题和金华区域赛A题(HDU 4442)是一样的做法. 对两个奶牛进行分析,选择两个奶牛总花费少的方式排序. bool cmp(const X&a,const X&b){ return ...
- label同时设置sizeToFit,NSTextAlignmentCenter不起作用
问题:label要多行显示,按照这样子设置,iOS9以上work,iOS8无用 self.bookNameLabel.lineBreakMode = NSLineBreakByCharWrapping ...
- 概率dp初探
论文链接: http://wenku.baidu.com/link?url=vEcfxpqAvGRf6JL9IL2R6v8plBgPnaP3tKp5niOBmoajk0y4CcpwFzL4SkfGS ...
- CentOS6.5安装python redis模块
1.下载安装包https://pypi.python.org/packages/source/r/redis/redis-2.10.3.tar.gz 2.解压tar -zxf redis-2.10.3 ...
- java 容器、二叉树操作、107
二叉树本身固有的递归性质,通常可以用递归算法解决,虽然递归代码简介,但是性能不如非递归算法. 常用的操作是构建二叉树.遍历二叉树(先序.中序.后序.都属于DFS深度优先搜索算法,使用栈来实现),广度优 ...
- linux内核——1.概述
1.结构 linux中,我们把操作系统分为内核空间和用户空间.用户通过用户空间与操作系统打交道.用户要通过系统调用访问内核空间.下图为Linux体系结构,shell应该为在最顶层. 系统调用,下面链接 ...
- ashx文件中使用session提示“未将对象引用设置到对象的实例”
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Data;u ...
- UVa 10341 - Solve It
题目:给一个方程,求解方程的解.已给出解的范围,并且可知方程等号左侧的函数是递减的,可用二分法进行试探,直到得出给定误差范围内的解. #include <cstdio> #include ...
- 动态创建Fastreport(delphi)
动态创建Fastreport分以下几个步骤: 1.首先清空Fastreport,定义全局变量,并加载数据集 frReport.Clear; frReport.DataSets.Add(fr ...