不要在Android的Application對象中緩存數據!


前言

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

測試步驟

  1. 打開這個APP;

  2. 在WhatIsYourNameActivity中,你按要求輸入用戶名並將其緩存到MyApplication這個對象中;

  3. 接着在GreetLoudlyActivity中,程序從MyApplication對象中取出用戶名並顯示出來;

  4. 用戶按了Home按鍵離開了該APP;

  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來緩存數據,卻沒想到恢復APP時直接跑了B Activity而不是先啟動A Activity,最終導致的結果是程序意外的崩潰掉了。

有哪些替代方法可用呢?

  對於數據緩存問題我也沒有比較好的辦法,但你可以按照下面其中一種方式來處理:

  • 通過Intent在Activity之間來傳遞數據(但是請別傳遞大量數據,這有可能導致程序異常或者ANR);

  • 使用官方推薦的方法中的一種將數據持久化,存儲在磁盤中;

  • 在使用數據和句柄的時候做空值檢測;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM