在一个App里面总有一些数据须要在多个地方用到。这些数据多是一个 session token,一次费时计算的结果等。一般为了不activity之间传递对象的开销 ,这些数据通常都会保存到持久化存储里面。html
有人建议将这些数据保存到 Application 对象里面,这样这些数据对全部应用内的activities可用。这种方法简单,优雅并且……彻底扯淡。android
假设把你的数据都保存到Application对象里面去了,那么你的应用最后会以一个NullPointerException 异常crash掉。shell
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,咱们调用第一个activity设置并存在application里面的用户姓名:session
// 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。app
在 WhatIsYourNameActivity里面,要求用户输入姓名,并存储到 MyApplication。ide
在 GreetLoudlyActivity里面,你从MyApplication 对象中得到用户姓名,而且显示。测试
用户按home键离开这个app。ui
几个小时后,Android系统为了回收内存kill掉了这个app。到目前为止,一切尚好。接下来就是crash的部分了…
用户从新打开这个App。
Android系统建立一个新的 MyApplication 实例并恢复 GreetLoudlyActivity。
GreetLoudlyActivity 重新的 MyApplication 实例中获取用户姓名,可获得的为空,最后致使NullPointerException。
在上面这个例子中,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 。
使用官方推荐的几种方式将数据持久化到磁盘上。
在使用数据的时候老是要对变量的值进行非空检查。
进行本地数据保护,对apk应用的网络缓存、本地存储数据进行深度保护。
更新: Daniel Lew指出,kill app更简单的方式就是使用DDMS里面“中止进程” 。你在调试你的应用的时候可使用这招。
为了测试这个,你必须使用一个Android模拟器或者一台root过的Android手机。
使用home按钮退出app。
在终端里:
# 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)一样适用。