不要通过Application Object或者其他全局静态变量来存放数据
博客专区 > SuShine 的博客 > 博客详情
不要通过Application Object或者其他全局静态变量来存放数据
SuShine 发表于2年前
不要通过Application Object或者其他全局静态变量来存放数据
  • 发表于 2年前
  • 阅读 37
  • 收藏 0
  • 点赞 0
  • 评论 0

           不要通过Application Object或者其他全局静态变量来存放数据

 

    转载请注明来自:http://blog.csdn.net/liaoqianchuan00/article/details/24399093

翻译自:http://www.developerphil.com/dont-store-data-in-the-application-object/

 

概述

在我们的应用程序中,很多地方可能用到同一个数据。很多时候我们可能不想通过Intent在Activity之间传递或者持久化的存放这些数据来。

 

我们可能会将这些数据存放在Application对象中,这样我们就可以在所有的Activity中访问了。这个方法很简单,但是实际上是完全错误的。

 

你的程序可能会因为NullPointerException而crash掉,因为上面的方案是基于你假设你存放的数据一直都在那里的。

 

例子

Application对象:

 

// access modifiers omitted for brevity

class MyApplication extends Application {

 

    String name;

 

    String getName() {

        returnname;

    }

 

    void setName(String name) {

        this.name= name;

    }

}

 

在第一个Activity中,我们将一个用户的名字存放在Application中:

 

// access modifiers omitted for brevity

class WhatIsYourNameActivity extends Activity {

 

    void onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.writing);

 

        //Just assume that in the real app we would really ask it!

        MyApplicationapp = (MyApplication) getApplication();

        app.setName("DeveloperPhil");

        startActivity(newIntent(this, GreetLoudlyActivity.class));

 

    }

 

}

 

在第二个Activity中,我们取出这个用户的名字:

 

// access modifiers omitted for brevity

class GreetLoudlyActivity extends Activity {

 

    TextView textview;

 

    void onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

 

        setContentView(R.layout.reading);

        textview= (TextView) findViewById(R.id.message);

    }

 

    void onResume() {

        super.onResume();

 

        MyApplicationapp = (MyApplication) getApplication();

        textview.setText("HELLO" + app.getName().toUpperCase());

    }

}

 

场景

1.       用户打开程序。

2.       在WhatIsYourNameActivity中,你询问用户的名字,并且把它存放到Application中。

3.       在GreetLoudlyActivity中,你从MyApplication对象中取出用户的名字并且显示。

4.       用户按Home键离开我们的应用程序。

5.       数小时后,Android系统可能杀掉你的程序来获得更多的内存。

到现在为止,看起来都很正常。但是Crash马上就要发生了。

6.       用户重新打开程序。

7.       Android建立一个新的MyApplication实例,并且重新恢复GreetLoudlyActivity。

8.       GreetLoudlyActivity取得用户的名字,但是现在已经是null了,然后报错NullPointerException。

 

为什么会Crash?

在这个例子中,因为Application实例是重新创建的,所以name变量是null,导致我们在调用String->toUpperCase的时候报NullPointerException。

 

这就将我们引向了核心问题:Application对象不会一直在内存中存在,他可能被杀掉。和我们认为的相反,他不会恢复以前的信息。Android会创建一个新的Application对象,然后重新打开之前用户按Home离开的那个Activity。

 

这就是说,如果你假设Activity B不可能在Activity A之前开启,所以你保存数据在Application中,那么你的程序可能就会crash。

 

解决方案

1.       通过Intent在Activity之间传递数据。

2.       使用多种持久化保存数据的方式(文件,数据库,sharedpreference等)。

3.       做null判断,并且手动处理null的情况。

 

如何模拟应用程序被杀掉

1.       按Home键离开你的应用程序

2.       打开DDMS,选中你应用程序的进程,点击“stop process”。

3.       使用task switcher返回你的应用程序。现在你的应用程序的Application对象就是一个新的实例了。

 

总结

在Application对象中保存数据室错误的并且可能导致你的程序crash,使用Intent来传递数据或者将数据保存在disk上。

 

同时记住,这个问题同样适用于任何单例或者公共的静态变量。

 

 

备注:  在实际项目中却还是使用到了单例和静态变量, 所以可能导致后台很长时间之后崩溃, 现在的解决方案是

保存在Activity的成员变量 应该用 onsave存起来 单例 应该在i()中进行一次初始化

或者在 oncreate 重新初始化.

 

 

共有 人打赏支持
粉丝 118
博文 321
码字总数 79631
×
SuShine
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: