为什么不能往Android的Application对象里存储数据

在一个App里面总有一些数据需要在多个地方用到。这些数据可能是一个 session token,一次费时计算的结果等。通常为了避免activity之间传递对象的开销,这些数据一般都会保存到持久化存储里面。

有人建议将这些数据保存到Application对象里面,这样这些数据对所有应用内的activities可用。这种方法简单,优雅而且……完全扯淡。

假设把你的数据都保存到Application对象里面去了,那么你的应用最后会以一个NullPointerException 异常crash掉。

一个简单的测试案例代码

Application 对象:

// access modifiers omitted for brevityclass MyApplication extends Application {String name;String getName() {return name;}void setName(String name) {this.name = name;}}

第一个activity,我们往application对象里面存储了用户姓名:

// access modifiers omitted for brevityclass 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里面的用户姓名:

// access modifiers omitted for brevityclass 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());}}

测试场景为什么会Crash?

在上面这个例子中,app会crash得原因是这个 Application 对象是全新的,所以这个name 变量里面的值为 null,当调用String#toUpperCase()方法时就导致了NullPointerException。

整个问题的核心在于:application 对象不会一直呆着内存里面,它会被kill掉。与大家普遍的看法不同之处在于,,实际上app不会重新开始启动。Android系统会创建一个新的Application 对象,然后启动上次用户离开时的activity以造成这个app从来没有被kill掉得假象。

你以为你的application可以保存数据,却没想到你的用户在没有打开activity A 之前就就直接打开了 activity B ,于是你就收到了一个 crash的surprise。

有哪些替代方法呢?

这里没啥神奇的解决方法,你可以试试下面几种方法:

如果模拟App被Kill掉

更新:Daniel Lew指出,kill app更简单的方式就是使用DDMS里面“停止进程”。你在调试你的应用的时候可以使用这招。

为了测试这个,你必须使用一个Android模拟器或者一台root过的Android手机。

使用home按钮退出app。在终端里:

# find the process idadb 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:# USERPID PPID VSIZE RSSWCHAN PCNAME# u0_a198 21997 160 827940 22064 ffffffff 00000000 S your.app.package # Kill the app by PIDadb 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对象里存储数据

相关文章:

你感兴趣的文章:

标签云: