Android提供多種方式儲存應用資料,其中一種方式是SharedPreferences,使用鍵值對儲存私有基本的資料。所有的邏輯僅基於以下三個類:
SharedPreference
SharedPreference在這三個類是最重要的,負責獲取(解析)儲存資料。提供獲取物件的編輯介面,在OnSharedPreferenceChangeListener中提供增加移出物件的介面。
- 建立SharedPreference物件,需要上下文物件(可以是應用程式的上下文)。
- getSharedPreferences 方法解析配置檔案並建立相關的物件對映。
- 通過上下文有多種建立它,強烈建議使用MODE_PRIVATE。因為建立一個可讀寫的檔案是非常危險的,容易在應用中產生安全漏洞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
; html-script: false ] // parse Preference file SharedPreferences preferences = context.getSharedPreferences("<span class="skimlinks-unlinked">com.example.app", Context.MODE_PRIVATE); // get values from Map preferences.getBoolean("key", defaultValue) preferences.get..("key", defaultValue) // you can get all Map but be careful you must not modify the collection returned by this // method, or alter any of its contents. Map<String, ?> all = preferences.getAll(); // get Editor object SharedPreferences.Editor editor = preferences.edit(); //add on Change Listener preferences.registerOnSharedPreferenceChangeListener(mListener); //remove on Change Listener preferences.unregisterOnSharedPreferenceChangeListener(mListener); // listener example SharedPreferences.OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener =newSharedPreferences.OnSharedPreferenceChangeListener() { @Override publicvoidonSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } }; |
Editor
SharedPreferences.Editor是用來修改SharedPreferences物件值的介面。你在editor 做出的修改都是待處理的,並沒有被複制到SharedPreferences裡,直到你呼叫commit()或apply()修改才會被執行。
- 使用簡單的介面在Editor放入值。
- 同步儲存資料使用commit() 方法或者非同步儲存資料使用apply()方法會更快點。實際上不同的執行緒使用commit()會更快點,這是我喜歡使用commit()方法的原因。
- 移出資料使用remove()方法,清除所有資料使用clear()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
; html-script: false ] // get Editor object SharedPreferences.Editor editor = preferences.edit(); // put values in editor editor.putBoolean("key", value); editor.put..("key", value); // remove single value by key editor.remove("key"); // remove all values editor.clear(); // commit your putted values to the SharedPreferences object synchronously // returns true if success booleanresult = editor.commit(); // do the same as commit() but asynchronously (faster but not safely) // returns nothing editor.apply(); |
效能和注意事項
SharedPreferences是單例物件,你可以很容易獲取你想要的引用。只在你第一次呼叫getSharedPreferences方法時開啟檔案時,建立一個例項物件。
1 2 3 4 5 6 7 8 9 10 |
; html-script: false ] // There are 1000 String values in preferences SharedPreferences first = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 4 milliseconds SharedPreferences second = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 0 milliseconds SharedPreferences third = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE); // call time = 0 milliseconds |
SharedPreferences 是單例物件,你可以改變它的例項,不用擔心同一個物件資料會不同。
1 2 3 4 |
; html-script: false ] first.edit().putInt(”key”,15).commit(); intfirstValue = first.getInt(”key”,0));// firstValue is 15 intsecondValue = second.getInt(”key”,0));// secondValue is also 15 |
當你第一次呼叫get方法時,它解析物件並把放入map中,第二次獲取資料從map 中獲取,不需再解析。
1 2 3 4 5 6 7 8 9 10 11 12 |
; html-script: false ] first.getString(”key”,null) // call time = 147 milliseconds first.getString(”key”,null) // call time = 0 milliseconds second.getString(”key”,null) // call time = 0 milliseconds third.getString(”key”,null) // call time = 0 milliseconds |
記住Preference的資料越大,get、commit、apply、remove和clear方法耗時越長。所以強烈建議把儲存的資料分成小的物件。
當你的應用更新以後,你的Preferences不會被移除。所以有些情況下需要建立遷移資料的方案。比如,在應用啟動的時候,你的應用解析本地JSON資料,實現這個你需要做的僅僅是儲存標誌資料(該資料是否為本地資料)。一段時間後,你更新JSON資料釋出新的版本,使用者會更新應用程式但是不會下載新的JSON資料,因為已經在本地儲存了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
; html-script: false ] publicclassMigrationManager { privatefinalstaticString KEY_PREFERENCES_VERSION ="key_preferences_version"; privatefinalstaticintPREFERENCES_VERSION =2; publicstaticvoidmigrate(Context context) { SharedPreferences preferences = context.getSharedPreferences("pref", Context.MODE_PRIVATE); checkPreferences(preferences); } privatestaticvoidcheckPreferences(SharedPreferences thePreferences) { finaldoubleoldVersion = thePreferences.getInt(KEY_PREFERENCES_VERSION,1); if(oldVersion < PREFERENCES_VERSION) { finalSharedPreferences.Editor edit = <spanclass="skimlinks-unlinked">thePreferences.edit</span>(); <spanclass="skimlinks-unlinked">edit.clear</span>(); edit.putInt(KEY_PREFERENCES_VERSION, currentVersion); edit.commit(); } } } |
SharedPreferences 資料儲存在app資料夾下的xml檔案下。
1 2 3 4 5 6 |
; html-script: false ] // yours preferences /data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PREFS_NAME.xml // default preferences /data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME_preferences.xml |
示例程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
; html-script: false ] publicclassPreferencesManager { privatestaticfinalString PREF_NAME ="<span class="skimlinks-unlinked">com.example.app.PREF_NAME"; privatestaticfinalString KEY_VALUE ="<span class="skimlinks-unlinked">com.example.app.KEY_VALUE"; privatestaticPreferencesManager sInstance; privatefinalSharedPreferences mPref; privatePreferencesManager(Context context) { mPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } publicstaticsynchronizedvoidinitializeInstance(Context context) { if(sInstance ==null) { sInstance =newPreferencesManager(context); } } publicstaticsynchronizedPreferencesManager getInstance() { if(sInstance ==null) { thrownewIllegalStateException(PreferencesManager.class.getSimpleName() + " is not initialized, call initializeInstance(..) method first."); } returnsInstance; } publicvoidsetValue(longvalue) { mPref.edit() .putLong(KEY_VALUE, value) .commit(); } publiclonggetValue() { returnmPref.getLong(KEY_VALUE,0); } publicvoidremove(String key) { mPref.edit() .remove(key) .commit(); } publicbooleanclear() { returnmPref.edit() .clear() .commit(); } } |
本文程式碼可以在github上找到。