Android之SharePreferences數據存儲

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

8.參考資料

參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章