【安卓开发】为什么不能往Android的Application对象里存储数据
在一个App里面总有一些数据需要在多个地方用到。这些数据可能是一个 session token,一次费时计算的结果等。通常为了避免activity之间传递对象的开销 ,这些数据一般都会保存到持久化存储里面。
有人建议将这些数据保存到 Application 对象里面,这样这些数据对所有应用内的activities可用。这种方法简单,优雅而且……完全扯淡。
假设把你的数据都保存到Application对象里面去了,那么你的应用最后会以一个NullPointerException 异常crash掉。
一个简单的测试案例
代码
Application 对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// access modifiers omitted for brevity class MyApplication extends Application { String name; String getName() { return name; } void setName(String name) { this .name = name; } } |
第一个activity,我们往application对象里面存储了用户姓名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 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,我们调用第一个activity设置并存在application里面的用户姓名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 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。
- 几个小时后,Android系统为了回收内存kill掉了这个app。到目前为止,一切尚好。接下来就是crash的部分了…
- 用户重新打开这个App。
- Android系统创建一个新的 MyApplication 实例并恢复 GreetLoudlyActivity。
- GreetLoudlyActivity 从新的 MyApplication 实例中获取用户姓名,可得到的为空,最后导致NullPointerException。
为什么会Crash?
在上面这个例子中,app会crash得原因是这个 Application 对象是全新的,所以这个name 变量里面的值为 null,当调用String#toUpperCase() 方法时就导致了NullPointerException。
整个问题的核心在于:application 对象不会一直呆着内存里面,它会被kill掉。与大家普遍的看法不同之处在于,实际上app不会重新开始启动。Android系统会创建一个新的Application 对象,然后启动上次用户离开时的activity以造成这个app从来没有被kill掉得假象。
你以为你的application可以保存数据,却没想到你的用户在没有打开activity A 之前就就直接打开了 activity B ,于是你就收到了一个 crash 的 surprise。
有哪些替代方法呢?
这里没啥神奇的解决方法,你可以试试下面几种方法:
- 直接将数据通过intent传递给 Activity 。
- 使用官方推荐的几种方式将数据持久化到磁盘上。
- 在使用数据的时候总是要对变量的值进行非空检查。
如果模拟App被Kill掉
更新: Daniel Lew指出,kill app更简单的方式就是使用DDMS里面“停止进程” 。你在调试你的应用的时候可以使用这招。
为了测试这个,你必须使用一个Android模拟器或者一台root过的Android手机。
- 使用home按钮退出app。
- 在终端里:
123456789101112131415
# find the process id
adb shell
ps
# then find the line with the package name of your app
# Mac/Unix: save some time by using grep:
adb shell
ps
|
grep
your.app.package
# The result should look like:
# USER PID PPID VSIZE RSS WCHAN PC NAME
# u0_a198 21997 160 827940 22064 ffffffff 00000000 S your.app.package
# Kill the app by PID
adb shell
kill
-9 21997
# the app is now killed
- 长按home按钮回到之前的app。
你现在是出于一个新的application实例中了。
总结
不要在application对象里面储存数据,这容易出错,导致你的app crash。
要么将你后面要用的数据保存到磁盘上面或者保存到intent得extra里面直接传递给activity 。
这些结论不但对application对象有用,对你app里面的单例对象(singleton)或者公共静态变量(public static)同样适用。
【安卓开发】为什么不能往Android的Application对象里存储数据的更多相关文章
- 为什么不能往Android的Application对象里存储数据
在一个App里面总有一些数据需要在多个地方用到.这些数据可能是一个 session token,一次费时计算的结果等.通常为了避免activity之间传递对象的开销 ,这些数据一般都会保存到持久化存储 ...
- 不要在Android的Application对象中缓存数据!
前言 在你的App中的很多地方都需要使用到数据信息,它可能是一个session token,一次费时计算的结果等等,通常为了避免Activity之间传递数据的开销,会将这些数据通过持久化来存储. ...
- 安卓开发_浅谈Android动画(四)
Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1. ValueAnimator 基本属 ...
- Android 利用Application对象存取公共数据
本文章来给大家介绍Android 利用Application对象存取公共数据. Android系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量. ...
- 安卓开发第一步:Android Studio安装配置
虽然本人是JAVA开发工程师平时主要开发Web App,但因为项目需求需要开发对应的移动端.一时又找不到合适的安卓开发人员,兄弟我只好被项目经理"抓来当壮丁了".俗话说好" ...
- Application对象的使用-数据传递以及内存泄漏
Application的使用 What is Application Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创 ...
- 【Bugly安卓开发干货分享】Android APP 快速 Pad 化实现
项目背景 采用最新版本手机 APP(之后称为 MyApp)代码,实现其 Pad 化,为平板和大屏手机用户提供更好的体验.为实现 MyApp 的 Pad 化工作,需要我们首先来了解一下 MyApp 项目 ...
- 重拾安卓_01_安卓开发环境搭建(android studio)
一.下载安装SDK 参考:搭建Android开发环境——Eclipse 的安装SDK部分 二.安装android studio 参考: Android Studio 入门级教程(一) 三.andro ...
- 安卓开发学习日记 DAY2——android项目文件
当一个android项目建立时,会有一个目录,以下为目录所包含内容 src:放置java源代码 gen:基本不会做任何更改,放置自动生成的配置文件(主要是R文件) Android4.4.2:放置当前版 ...
随机推荐
- [LeetCode] Convert BST to Greater Tree 将二叉搜索树BST转为较大树
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...
- 出错信息:Incorrect string value: '\xE4\xBD\xA0\xE5\xA5\xBD' for column 'username'
出错信息: java.sql.SQLException: Incorrect string value: '\xE4\xBD\xA0\xE5\xA5\xBD' for column 'username ...
- ●POJ 2794 Double Patience
题链: http://poj.org/problem?id=2794题解: 状压DP,概率 9元组表示每一堆还剩几张牌.可以用5进制状压,共5^9=1953124个状态. 令P(S)表示S这个状态被取 ...
- hdu 5468(莫比乌斯+搜索)
hdu 5468 Puzzled Elena /*快速通道*/ Sample Input 5 1 2 1 3 2 4 2 5 6 2 3 4 5 Sample Output Case #1: ...
- [UOJ UNR#2 UOJ拯救计划]
来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 感觉这题有点神... 模数是6比较奇怪,考虑计算答案的式子. Ans=$\sum_{i=1}^{k} P(k,i)*ans(i)$ a ...
- [bzoj4405][wc2016]挑战NPC
来自FallDream的博客,未经允许,请勿转载,谢谢. 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个球,用整数1到n编号.还有m个筐子,用整数1到m编号. ...
- Visual Studio 2015 无法命中断点
新安装操作系统后发现,vs2015无法命中断点. 在项目中设置生成调试信息:FULL 即可.
- SpringCloud学习之zuul
一.为什么要有网关 我们先看一个图,如果按照consumer and server(最初的调用方式),如下所示 这样我们要面临如下问题: 1. 用户面临着一对N的问题既用户必须知道每个服务.随着服务的 ...
- 从零开始搭建口袋妖怪管理系统(2)-借助ngRoute实现详情页面跳转
一.目标 上一次我们用Angular1.x完成了简单的口袋妖怪展示列表页面,现在我们想要了解口袋妖怪更多的信息,但是发现原有单行表格可能容纳不下口袋妖怪的所有信息,所以现在我们需要一个口袋妖怪详情界面 ...
- React .js框架的环境搭建
React学习笔记(一)- 环境搭建 最近在学习react相关的知识,刚刚起步,一路遇坑不断.自己做个笔记,方便日后总结,也供相同趣味的小伙伴一起交流探讨. 学习时主要参考官网的教程:https: ...