天天看點

關于 SharedPreferences 的一些思考

對于 SharedPreferences ,想必不會陌生,通常我們會這麼用

Editor sharedata = getSharedPreferences("data", 0).edit();
sharedata.putString("item","hello getSharedPreferences");
sharedata.commit();
           

SharedPreferences 的百度定義如下:

SharedPreferences是Android平台上一個輕量級的存儲類,用來儲存應用的一些常用配置,比如Activity狀态,Activity暫停時,将此activity的狀态儲存到SharedPereferences中;當Activity重載,系統回調方法onSaveInstanceState時,再從SharedPreferences中将值取出。

SharedPreferences提供了java正常的Long、Int、String等類型資料的儲存接口。 [1] SharedPreferences類似過去Windows系統上的ini配置檔案,但是它分為多種權限,可以全局共享通路。

提示最終是以xml方式來儲存,整體效率來看不是特别的高,對于正常的輕量級而言比SQLite要好不少,如果真的存儲量不大可以考慮自己定義檔案格式。xml處理時Dalvik會通過自帶底層的本地XML Parser解析,比如XMLpull方式,這樣對于記憶體資源占用比較好。

原理:

内部是以 XML 結構儲存在 /data/data/包名/shared_prefs 檔案夾下,資料以鍵值對的形式儲存。

檔案内容:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <boolean name="first_login" value="false" />
</map>
           

送出方式:

apply:異步執行,沒有傳回值;

commit:同步執行,有傳回值。

建立模式:

MODE_PRIVATE:預設模式,該模式下建立的檔案隻能被目前應用或者與該應用具有相同SharedUserID的應用通路。

MODE_WORLD_READABLE:允許其他應用讀取這個模式建立的檔案。在Android N上使用該模式将抛出SecurityException異常。

MODE_WORLD_WRITEABLE:允許其他應用寫入這個模式建立的檔案。在Android N上使用該模式将抛出SecurityException異常。

MODE_APPEND:如果檔案已經存在了,則在檔案的尾部添加資料。

MODE_MULTI_PROCESS:SharedPreferences加載标志,當設定了該标志,則在磁盤上的檔案将會被檢查是否修改了,盡管SharedPreferences執行個體已經在該程序中被加載了。(雞肋,不要用,推薦用ContentProvider)

到此,基本的使用上已經沒什麼問題了,對于部配置設定置參數的存取上,都可以通過這些來實作。

SharedPreferences 真的就這些内容嗎?

并不是,它還有

registerOnSharedPreferenceChangeListener、unregisterOnSharedPreferenceChangeListener 設定監聽

getAll 擷取所有的鍵值對

更有提供的preference以鍵值對的方式來處理這種情況:自動儲存設定的資料,并立時生效。實作即為使用 SharedPreferences 。

常見的Preference控件有:

直接子類:DialogPreference, PreferenceGroup, RingtonePreference, TwoStatePreference

非直接子類:CheckBoxPreference, EditTextPreference, ListPreference, MultiSelectListPreference, PreferenceCategory, PreferenceScreen, SwitchPreference

注意,在API 29 開始被棄用,使用上需注意。

在看ACRA項目時有看到使用registerOnSharedPreferenceChangeListener來設定監聽,以此實作開關功能,這用法真是巧妙,因為這個解決了耦合的問題,通常情況下,我們設定一個開關如下:

public class A{
	private boolean isEnable = false;
	...
	public void setEnable(boolean enable){
		this.isEnable = enable;
	}
	...
}
           

這種方式顯而易見,容易。

使用時,隻需要拿到執行個體操作即可

A a = new A();
a.setEnable(true);
           

在學習開源項目ACRA時,看到如下用法

final SharedPreferences prefs = new SharedPreferencesFactory(app, config).create();
...
ErrorReporterImpl reporter = new ErrorReporterImpl(app, config, enableAcra, supportedAndroidVersion, checkReportsOnApplicationStart);
prefs.registerOnSharedPreferenceChangeListener(reporter);
...
           

其中,reporter對象為一個錯誤捕獲實作,實作了SharedPreferences.OnSharedPreferenceChangeListener,其代碼如下,

@Override
public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferences, @Nullable String key) {
    if (ACRA.PREF_DISABLE_ACRA.equals(key) || ACRA.PREF_ENABLE_ACRA.equals(key)) {
        setEnabled(SharedPreferencesFactory.shouldEnableACRA(sharedPreferences));
    }
}
           

是不是忽然有個大膽的想法

如果在項目中,我的一些控制器在上層想設定某個啟用與否,可以通過此方式進行解耦控制,大大降低了子產品與子產品的聯系,進而在一些功能的更新、子產品的修改上更加友善,無需考慮關聯性修改的問題。

希望SharedPreferences的這種用法對你有用😊