Application對象中存儲的數據一直存在?


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


千萬不要把數據存儲在Application對象中


may 5, 2013
在我們的應用程序中有些數據需要在多處使用。有可能是一個會話令牌,花費很大代價才得來的結果,等等。而且我們總是想避免在兩個Activity之間傳遞數據或者不想把數據存儲在持久存儲器中。

一個解決問題的模式是把數據存儲在應用的Application對象中,這樣呢存儲的數據就能在所有的Activity中共享。這種解決辦法看起來很簡單,很優雅,但其實是錯誤的!

如果你始終相信數據一直會待在Application對象中,那麼你的應用最終會因爲NullPointerException異常而終止。

一個很簡單的測試案例


The Application object:

// access modifiers omitted for brevity
classMyApplication extends Application {
 
    String name;
 
    String getName() {
        returnname;
    }
 
    voidsetName(String name) {
        this.name = name;
    }
}
The first activity, where we store the name of the user in the application object:

// access modifiers omitted for brevity
classWhatIsYourNameActivity extends Activity {
 
    voidonCreate(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(newIntent(this, GreetLoudlyActivity.class));
 
    }
 
}

The second activity, where we shout the name of the user:

// access modifiers omitted for brevity
classGreetLoudlyActivity extends Activity {
 
    TextView textview;
 
    voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.reading);
        textview = (TextView) findViewById(R.id.message);
    }
 
    voidonResume() {
        super.onResume();
 
        MyApplication app = (MyApplication) getApplication();
        textview.setText("HELLO " + app.getName().toUpperCase());
    }
}


用戶使用你應用可能的場景


     1、用戶打開你的應用
     2、在WhatIsYourNameActivity中,你把用戶的名字存儲在MyApplication對象中
     3、在GreetLoudlyActivity中,你從MyApplication對象中把用戶的名字提取出來並顯示給用戶
     4、用戶按下home鍵離開了你的應用
     5、在幾個小時後,Android可能會在後臺默默地把你的應用殺死,釋放內存給其它應用使用
     到目前爲止並不會出現啥問題,你的應用也沒有出現任何異常
     6、用戶重新打開了你的應用
     7、Android會重新創建一個MyApplication對象和恢復GreeLoudlyActivity
     8、GreetLoudlyActivity獲取用戶的名字,但現在用戶名字已經是null,你的應用拋出NullPointerException異常終止


爲什麼會異常終止


在例子程序中,由於Application對象是新創建出來的,name屬性爲null,調用String#toUpperCase()  導致NullPointerException

發生問題的核心:Application對象不會永遠存在於內存中,可能會被回收殺死。普遍的看法是應用不會從頭重新啓動。Android會創建一個新的Application對象並且恢復之前的Activity,給用戶一個錯覺是應用永遠都不會被殺死,一直停留在原先的狀態

這意味着如果你期待用戶不會在打開Activity A之前打開Activity B,數據一直會在Application對象中。那麼你會得到一個異常終止的驚喜!

解決辦法


這裏沒有很好的解決方案,但是你可以遵循以下一些準則:

     1、使用intent明確的在Activity之間傳遞數據
     2、使用many ways 中的一種來在磁盤上存儲數據
     3、總是手動來進行null-check


怎樣來模擬應用程序被殺


EDIT:Daniel Lew 指出一個最簡單的方法是在DDMS中使用“Stop Process”功能來殺死一個應用(設備在debug模式)

要測試這個,你必須需要有一個模擬器或一臺root過的手機

   1、使用home鍵來退出你的應用
   2、在命令行敲入如下命令

# 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

   3、使用任務切換功能重新回到你的應用,現在你的應用就重新創建了Application對象


總結


在Application對象中存儲數據容易出錯,讓你的應用異常終止

如果數據在後面會被使用到,你可以存儲在磁盤中或者通過intent’s extras傳遞到需要的Activity中

另外還要注意的是對於Application對象來說是這種情況,那麼對於任何單例對象或者靜態屬性來說都如此

注:經過自己的測試,確實出現如作者所描述的情況










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章