决不在Android的Application对象中缓存数据

说明

  这是翻译老外的大器晚成篇小说,笔者在此之前有境遇过那么些难题,况兼拜见有人在Segmentfault上问,最要紧本身在StackOverflow上以至没搜到累死难点,所以以为有必不可缺翻译过来以便前边不会再如此管理。

前言

  在您的App中的比非常多地点都亟需利用到多少消息,它大概是七个session
token,一遍艰巨总结的结果等等,经常为了幸免Activity之间传递数据的开支,会将那个数据经过悠久化来存款和储蓄。

  有人提出将那个多少放在Application对象中有益具有的Activity访谈,那么些建设方案大概、高贵同一时间是……完全错误的。

  你假诺你将数据缓存到Application对象中,那么有比非常大可能率您的主次最后会由于一个NullPointerException相当而夭折掉。

前言

  在您的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());
    }
}

四个简约的测量检验程序

  那是自定义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());
    }
}

测量试验步骤

  1. 张开这一个应用软件;

  2. 在WhatIsYourNameActivity中,你按要求输入顾客名并将其缓存到MyApplication那一个目的中;

  3. 随后在GreetLoudlyActivity中,程序从MyApplication对象中抽出客商名并突显出来;

  4. 客商按了Home开关离开了该应用软件;

  5. 数钟头过后,系统由于内部存款和储蓄器不足(顾客在经验其余应用软件呢,前台的天职接二连三优先的嘛)会在后台将你的程序杀掉;在你重新开动该应用程式以前风姿洒脱切看起来很好,不过…..;

  6. 新普京娱乐场,客户重新张开了这么些应用软件;

  7. Android会重新创造二个此前被Kill掉的MyApplication实例并回复GreetLoudlyActivity;

  8. GreetLoudlyActivity去获得顾客名时,会因为获取的为空值报NullPointerException而夭亡掉。

测量试验步骤

  1. 开荒那几个应用软件;

  2. 在WhatIsYourNameActivity中,你按必要输入顾客名并将其缓存到MyApplication那几个目的中;

  3. 进而在GreetLoudlyActivity中,程序从MyApplication对象中抽出客户名并展现出来;

  4. 客户按了Home按钮离开了该应用软件;

  5. 数时辰过后,系统由于内部存款和储蓄器不足(客商在心得别样APP呢,前台的天职三番五次优先的呗)会在后台将您的主次杀掉;在您重新开动该APP以前大器晚成切看起来很好,不过…..;

  6. 顾客重新展开了这些APP;

  7. Android会重新制造二个早先被Kill掉的MyApplication实例并苏醒GreetLoudlyActivity;

  8. GreetLoudlyActivity去赢得客户名时,会因为获取的为空值报NullPointerException而夭亡掉。

为啥会如此?

  在上边这一个事例中,程序之所以会崩溃掉是因为恢复生机之后APP的Application对象是斩新的,所以缓存在Application中的客户名成员变量为空值,在前后相继调用String的toUpperCase()方法时出于NullPointerException而夭亡掉。

  导致那一个题指标重大缘由是:Application对象并不是始终在内部存款和储蓄器中的,它有极大可能率会由于系统内存不足而被杀掉。但Android在您回复
这一个利用时并非重复起先起步这些动用,它会创建一个新的Application对象并且运维上次客户间隔时的activity以促成这些app平昔不曾
被kill掉得假象。

  我们感觉能够经过Application来缓存数据,却没悟出恢复生机应用软件时直接跑了B
Activity并非先运维A Activity,最后变成的结果是前后相继竟然的咽气掉了。

怎会这么?

  在地点那一个事例中,程序之所以会崩溃掉是因为苏醒之后APP的Application对象是全新的,所以缓存在Application中的客户名成员变量为空值,在前后相继调用String的toUpperCase()方法时由于NullPointerException而咽气掉。

  导致这一个题指标要害缘由是:Application对象并不是始终在内部存款和储蓄器中的,它有极大希望会由于系统内部存储器不足而被杀掉。但Android在您回复这么些利用时并不是再次开端起步这些动用,它会创立三个新的Application对象并且运营上次客户间距时的activity以促成这些app平昔不曾被kill掉得假象。

  大家认为能够经过Application来缓存数据,却没悟出恢复生机应用软件时直接跑了B
Activity实际不是先运维A Activity,最后形成的结果是前后相继竟然的夭亡掉了。

有啥样代替情势可用呢?

  对于数据缓慰劳题自个儿也未曾比较好的办法,但您能够遵守下边个中生气勃勃种方法来拍卖:

  • 由此Intent在Activity之间来传递数据(不过请别传递大量多少,那有十分的大可能产生程序非常大概ANLAND);

  • 使用官方推荐的方法中的大器晚成种将数据漫长化,存款和储蓄在磁盘中;

  • 在应用数据和句柄的时候做空值质量评定;

有怎样替代格局可用呢?

  对于数据缓慰问题我也从没相比较好的法子,但您可以根据上面此中意气风发种艺术来拍卖:

  • 经过Intent在Activity之间来传递数据(不过请别传递大量数码,这有相当的大希望导致程序极度只怕ANTiguan);

  • 使用官方推荐的方法中的生气勃勃种将数据长久化,存款和储蓄在磁盘中;

  • 在接纳数据和句柄的时候做空值检查测验;

怎么模拟应用程序被杀掉?

更新:Daniel
Lew
提出,最简便的方法是在DDMS中式茶食击”Stop
Porcess”杀掉你的次序,在你调节和测验程序的时候能够这么做。

  你能够透过模拟器只怕二个Root过的真机来测量检验实际效果:

  1. 按Home按键退出你的次第;

  2. 在调节台,敲入如下命令(Windows系统下 WIN + XC60 -> cmd -> 回车)

     # 找到该APP的进程ID
     adb shell ps
     # 找到你APP的报名
    
     # Mac/Unix: save some time by using grep:
     adb shell ps | grep your.app.package
    
     # 按照上述命令操作后,看起来是这样子的: 
     # USER      PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
     # u0_a198   21997 160   827940 22064 ffffffff 00000000 S your.app.package
    
     # 通过PID将你的APP杀掉
     adb shell kill -9 21997
    
     # APP现在被杀掉啦
    
  3. 当今在桌面长按Home开关通过后台任务管理器张开你的应用软件,此时系统就能够重复创立贰个MyApplication实例了。

总结

  不要在Application对象中缓存数据化,那有希望会变成您的顺序崩掉。请使用Intent在各组件之间传递数据,抑或是将数据存款和储蓄在磁盘中,然后在急需的时候抽取来。

  并不仅仅唯有Application对象是如此的,别的的单例恐怕国有静态类也是有非常大概率会出于系统内部存储器而被杀掉,谨记。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图