在應用程式間及與使用者的通訊互動過程中,會產生並傳遞一系列資料。針對這些資料,有部分是隻在應用程式中使用的快取資料,還有一部分是在不同位置多次或長時間使用的持久化資料。

對於快取資料來說,通常以程式碼中定義區域性變數或全域性變數的方式訪問使用,這種使用方式伴隨在程式設計的整個過程中;而持久化資料,則需要以特定的檔案格式儲存在系統硬碟中,使用系統提供的框架方法來訪問使用。而根據要持久化儲存資料的複雜程度不同,分別有輕量級SharedPreferences,資料庫SQLiteOpenHelper或其封裝的Room,以及二進位制訪問的檔案File這三種方式。本文主要對持久化資料的幾種不同型別簡做介紹。

輕量級SharedPreferences

對於輕量級的鍵值對資料,可以使用android.content.SharedPreferences共享選項介面實現的相關類以持久化儲存。

SharedPreferences形式儲存的資料,將會以 key-value 鍵值對的形式,基於 xml 格式的檔案儲存在當前應用的內部儲存空間中。這種應用程式的內部儲存空間中的檔案,只允許其所屬應用程式讀寫。而當應用程式解除安裝後,或通過 系統桌面 - 設定 - 應用管理 - 當前應用程式 - 應用資料 - 清除資料 系列操作後,其內部儲存空間也將被清空。這在一定程度上保證了內部儲存空間的資料安全。

建立檔案

在AndroidSDK中已經定義SharedPreferencesImpl類作為SharedPreferences介面的實現類。

對於SharedPreferences介面的例項化物件,在可以訪問上下文環境Context物件的地方,可通過呼叫Context物件的getSharedPreferences(String name, int mode)方法獲取。其對應的 xml 格式檔案將在當前應用程式整個生命週期過程中讀寫訪問。

或者也可以在Activity介面中,呼叫Activity物件的getPreferences(int mode)方法獲取,其對應的 xml 檔案只在當前介面生命週期中讀寫訪問。

getSharedPreferences(String name, int mode)方法中,

引數 name 指定儲存當前資料的 xml 格式檔案的檔名,其值可由開發者定義。

引數 mode 為檔案的開啟方式,其值通常為僅允許當前應用程式訪問該檔案的Context.MODE_PRIVATE=0;在Android6.0即API23之前,該值也可以為允許多程序讀寫同步的Context.MODE_MULTI_PROCESS=4,然而該模式下會出現各種異常問題,故此版本後被棄用;在Android4.2即API17之前,mode 值也可以為允許其他應用程式讀該檔案的Context.MODE_WORLD_READABLE=1,和允許其他應用程式寫該檔案的Context.MODE_WORLD_WRITEABLE=2,但這兩個值均不能保證當前應用程式的資料安全性,故此版本之後被棄用。

另外,如果看不慣系統定義的SharedPreferencesImpl實現類,開發時完全可以自定義一個SharedPreferences介面的實現類,在使用context.getSharedPreferences(String name, int mode)獲取例項化物件的位置替換為自定義的實現類物件即可。

總之,在獲取SharedPreferences物件時,系統檢測當前應用程式內部儲存空間中是否有指定 namexml 格式檔案,若沒有將會先建立。之後系統便會開啟該檔案,通過SharedPreferences物件就可以讀寫該檔案了。

資料寫入檔案

如果想向建立的SharedPreferences物件所在檔案中寫入資料,只需要呼叫該物件的edit()方法,以獲取android.content.SharedPreferences.Editor介面型別的物件。

類似於介面間互動使用的Intent意圖中傳遞的資料方式,在SharedPreferences.Editor介面物件中,可以使用putBoolean(String key, boolean value)設定boolean型別的資料,putFloat(String key, float value)設定float型別的資料,putStringSet(String key, Set<String> values)設定String集合的資料等。這一系列的設定方法,其引數一 key 都是作為SharedPreferences檔案中唯一的String型別的值,以標記當前資料;其引數二 value 則是要持久化儲存的資料值。

另外,在SharedPreferences.Editor介面物件中,也可以使用remove (String key)方法以刪除存在的引數 key 所標記的資料內容。或者直接使用clear()方法清空設定的所有資料內容。

在通過SharedPreferences.Editor介面物件設定或刪除完資料後,呼叫其apply()commit()方法以一次性提交設定的所有資料,在提交之後系統會將上文設定的資料都儲存到SharedPreferences檔案中。

雖然commit()方法可以返回boolean值以判斷是否提交成功,但並不推薦使用該方法;使用apply()方法可以更安全的保證提交的資料成功儲存。

檔案讀取資料

如果想讀取SharedPreferences物件所在檔案的資料,就沒有將資料寫入檔案那麼繁瑣的步驟了。只需要直接呼叫SharedPreferences物件的getBoolean(String key, boolean defValue)獲取boolean型別的資料值,getFloat(String key, float defValue)獲取float型別的資料值,getStringSet(String key, Set<String> defValues)獲取Set<String>型別的資料值等。這一系列的獲取方法,其引數一 key 與寫入檔案時的設定方法中的引數 key 一致,以標記響應資料;引數二 defaultValue 則是預設的資料值,當SharedPreferences檔案中並沒有儲存引數 key 對應的資料時,將會返回 defaultValue 所設定的數值。

如果儲存的資料量並不多,也可以直接呼叫SharedPreferences物件的getAll()方法,獲取Map<String, ?>集合型別的所有資料,再對得到的資料分別操作處理。

另外SharedPreferences物件的contains(String key)方法,也可以只判斷當前SharedPreferences物件所在檔案中是否有引數 key 所標記的資料內容,返回boolean型別的結果。

檔案修改的實時監聽

可以用SharedPreferences物件的registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)方法,實時監聽當前SharedPreferences檔案的修改操作。

引數 listenerandroid.content.SharedPreferences.OnSharedPreferenceChangeListener介面的例項化物件,在該介面中實現了onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)方法。

一旦 listener 被註冊,在引數 sharedPreferences 對應的檔案中資料標記的 key 在被修改後, listener 中的onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)方法將會被系統回撥。

對於已經註冊的 listener ,尤其記得要在不需要監聽之後,呼叫SharedPreferences物件的unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener),將之前註冊的OnSharedPreferenceChangeListener物件撤銷掉,以防止在後續出現記憶體洩漏的問題。


輕量級的SharedPreferences儲存方式,可以很方便的儲存一些簡單資料,其記憶體效率是比較高的。然而如果應用程式中所有的資料都使用這種儲存方式,反而使SharedPreferences檔案的操作效率降低了,而且所有資料都使用這種鍵值對的形式存取,也會增加程式碼量。那麼有什麼更合適的儲存方式適合不同型別的資料嗎?詳情請關注下一篇文章。