SharedPreferences
SharedPreferences是一個輕量級的數據存儲,並以key-value鍵值對的形式存在,符合xml文件存儲
1.原型
public interface SharedPreferences
具體實現
//SharedPreferences其實是一個接口而已
public interface SharedPreferences {
//定義一個用於在數據發生改變時調用的監聽回調
public interface OnSharedPreferenceChangeListener {
//哪個key對應的值發生變化
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
//編輯SharedPreferences對象設定值的接口
public interface Editor {
//一些編輯存儲基本數據key-value的接口方法
Editor putString(String key, String value);
Editor putStringSet(String key, Set<String> values);
Editor putInt(String key, int value);
Editor putLong(String key, long value);
Editor putFloat(String key, float value);
Editor putBoolean(String key, boolean value);
//刪除指定key的鍵值對
Editor remove(String key);
//清空所有鍵值對
Editor clear();
//同步的提交到硬件磁盤
boolean commit();
//將修改數據原子提交到內存,而後異步提交到硬件磁盤
void apply();
}
//獲取指定數據
Map<String, ?> getAll();
String getString(String key, String defValue);
Set<String> getStringSet(String key, Set<String> defValues);
int getInt(String key, int defValue);
long getLong(String key, long defValue);
float getFloat(String key, float defValue);
boolean getBoolean(String key, boolean defValue);
boolean contains(String key);
//針對preferences創建一個新的Editor對象,通過它你可以修改preferences裏的數據,並且原子化的將這些數據提交回SharedPreferences對象
Editor edit();
//註冊一個回調函數,當一個preference發生變化時調用
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
//註銷一個之前(註冊)的回調函數
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}
2.方法
2.1 getPreferences(int mode)
public SharedPreferences getPreferences(int mode) {
return getSharedPreferences(getLocalClassName(), mode);
}
Activity的SharePreference實例獲取方法只是對Context的getSharedPreferences再一次封裝而已,使用getPreferences方法獲取實例默認生成的xml文件名字是當前activity類名而已,此方法爲Activity特有
2.2 getSharedPreferences (String name, int mode)
public abstract SharedPreferences getSharedPreferences (String name, int mode)
getSharedPreferences("config", Context.MODE_PRIVATE);
/data/data/com.example.reboottest/shared_prefs
下生成了一個config.xml文件
獲取SharedPreferences對象,其中第一參數爲數據存儲的文件名,並且會創建一個路徑(data/packagename/shared_prefs/),第二個參數爲Mode,具體有以下幾種模式
- MODE_APPEND
模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件
- MODE_MULTI_PROCESS
多進程之間的使用
- MODE_PRIVATE
默認的爲0,即MODE_PRIVATE
- MODE_WORLD_READABLE
表示當前文件可以被其他應用讀取
- MODE_WORLD_WRITEABLE
表示當前文件可以被其他應用寫入
2.3 edit()
getSharedPreferences(context).edit()
在訪問或修改數據之前需要先獲取一個編輯器,通過 SharedPreferences.Editor方法
2.4 onSharedPreferenceChanged
public abstract void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key)
當數據被增加,刪除,修改後會調用此接口
3.保存數據方式
- commit()
在寫操作commit時有三級鎖操作,所以效率很低,所以當我們一次有多個修改寫操作時等都批量put完了再一次提交確認,這樣可以提高效率。
public boolean commit() {
//1.先通過commitToMemory方法提交到內存
MemoryCommitResult mcr = commitToMemory();
//2.寫文件操作
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
//阻塞等待寫操作完成,UI操作需要注意!!!所以如果不關心返回值可以考慮用apply替代。
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
}
//3.通知數據發生變化了
notifyListeners(mcr);
//4.返回寫文件是否成功狀態
return mcr.writeToDiskResult;
}
- apply()
其實和commit類似,只不過他是異步寫的,沒在當前線程執行寫文件操作,還有就是他不像commit一樣返回文件是否寫成功狀態
public void apply() {
//有了上面commit分析,這個雷同,寫數據到內存,返回數據結構
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
public void run() {
try {
//等待寫文件結束
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
}
};
QueuedWork.add(awaitCommit);
//一個收尾的Runnable
Runnable postWriteRunnable = new Runnable() {
public void run() {
awaitCommit.run();
QueuedWork.remove(awaitCommit);
}
};
//這個上面commit已經分析過的,這裏postWriteRunnable不爲null,所以會在一個新的線程池調用postWriteRunnable的run方法
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
// Okay to notify the listeners before it's hit disk
// because the listeners should always get the same
// SharedPreferences instance back, which has the
// changes reflected in memory.
//通知變化
notifyListeners(mcr);
}
- commit與apply區別
return | method |
---|---|
abstract void | apply() |
abstract boolean | commit() |
1.apply沒有返回值,而commit有返回值boolean,表示是否提交成功
2.apply提交失敗後沒有任何提示
3.在SharedPreferences的Editor中如果用commit()方法提交數據,其過程是先把數據更新到內存,然後在當前線程中寫文件操作,提交完成返回提交狀態;如果用的是apply()方法提交數據,首先也是寫到內存,接着在一個新線程中異步寫文件,然後沒有返回值
4.數據存儲
4.1 寫數據
通過edit()方法獲取到haredPreferences.Editor編輯器
通過 putBoolean等方法添加數據,調用了Editor的putXXX後其實數據是沒有存入SharePreference的,具體如下表
return | method |
---|---|
abstract SharedPreferences.Editor | clear() |
abstract SharedPreferences.Editor | putBoolean(String key, boolean value) |
abstract SharedPreferences.Editor | putFloat(String key, float value) |
abstract SharedPreferences.Editor | putInt(String key, int value) |
abstract SharedPreferences.Editor | putLong(String key, long value) |
abstract SharedPreferences.Editor | putString(String key, String value) |
abstract SharedPreferences.Editor | putStringSet(String key, Set values) |
abstract SharedPreferences.Editor | remove(String key) |
最後commit保存修改,將Editor的數據存入SharePreference文件
public Editor putBoolean(String key, boolean value) {
//同步鎖操作
synchronized (this) {
//將我們要存儲的數據放入mModified集合中
mModified.put(key, value);
//返回當前對象實例,方便這種模式的代碼寫法:putXXX().putXXX();
return this;
}
}
4.2 讀數據
使用SharedPreferences對象來讀取數據,一旦拿到SharePreference對象之後的getXXX操作其實都不再是文件讀操作,如果讀取到數據後,則獲取,沒有的話,讀取默認的defValue默認值,具體代碼如下:
return | method |
---|---|
abstract boolean | getBoolean(String key, boolean defValue) |
abstract float | getFloat(String key, float defValue) |
abstract int | getInt(String key, int defValue) |
abstract long | getLong(String key, long defValue) |
abstract String | getString(String key, String defValue) |
abstract Set | getStringSet(String key, Set defValues) |
public boolean getBoolean(String key, boolean defValue) {
//可以看見,和上面異步load數據使用的是同一個對象鎖
synchronized (this) {
//阻塞等待異步加載線程加載完成notify
awaitLoadedLocked();
//加載完成後解析的xml數據放在mMap對象中,我們從mMap中找出指定key的數據
Boolean v = (Boolean)mMap.get(key);
//存在返回找到的值,不存在返回設置的defValue
return v != null ? v : defValue;
}
}
6.實例演示
登錄成功,保存對應的用戶名及密碼,登錄不成功提示登錄不成功,具體流程圖如下:
MyPref.xml
at MyPref.xml <
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="user">admin</string>
<string name="pwd">123456</string>
</map>
7.項目代碼
項目演練代碼:https://github.com/409144245/SharedPerfTest