雖然SharedPreferences用起來比較方便,但是在一些特殊場景會產生問題。比如共用引數儲存的資料較多時,初始化共用引數會把整個檔案載入進記憶體,載入耗時可能導致主執行緒堵塞。又如呼叫apply方法儲存資料時,頻繁apply容易導致執行緒等待超時。為此Android官方推出了資料倉儲DataStore,並將其作為Jetpack庫的基礎元件。DataStore提供了兩種實現方式,分別是Preferences DataStore 和Proto DataStore,前者採用鍵值對儲存資料,後者採用自定義型別儲存資料,其中Preferences DataStore可以直接替代SharedPreferences。
由於DataStore並未整合到SDK中,而是作為第三方框架提供,因此首先要修改模組的build.gradle檔案,往dependencies節點新增下面兩行設定,表示匯入指定版本的DataStore庫:
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"
資料倉儲的用法類似於共用引數,首先要指定倉庫名稱,並建立倉庫範例,範例程式碼如下:
private RxDataStore<Preferences> mDataStore; // 宣告一個資料倉儲範例
private DatastoreUtil(Context context) {
mDataStore = new RxPreferenceDataStoreBuilder(context.getApplicationContext(), "datastore").build();
}
// 獲取資料倉儲工具的範例
public static DatastoreUtil getInstance(Context context) {
if (instance == null) {
instance = new DatastoreUtil(context);
}
return instance;
}
其次從倉庫範例中獲取指定鍵名的資料,下面的程式碼模板演示瞭如何從資料倉儲中讀取字串值:
// 獲取指定名稱的字串值
public String getStringValue(String key) {
Preferences.Key<String> keyId = PreferencesKeys.stringKey(key);
Flowable<String> flow = mDataStore.data().map(prefs -> prefs.get(keyId));
try {
return flow.blockingFirst();
} catch (Exception e) {
return "";
}
}
往倉庫範例寫入指定鍵值的話,下面的程式碼模板演示瞭如何將字串值寫入資料倉儲:
// 設定指定名稱的字串值
public void setStringValue(String key, String value) {
Preferences.Key<String> keyId = PreferencesKeys.stringKey(key);
Single<Preferences> result = mDataStore.updateDataAsync(prefs -> {
MutablePreferences mutablePrefs = prefs.toMutablePreferences();
mutablePrefs.set(keyId, value);
return Single.just(mutablePrefs);
});
}
前面把資料倉儲的初始化以及讀寫操作封裝在DatastoreUtil中,接下來通過該工具類即可方便地存取資料倉儲了。往資料倉儲儲存資料的程式碼範例如下:
// 從資料倉儲中讀取資訊
private void readDatastore() {
DatastoreUtil datastore = DatastoreUtil.getInstance(this); // 獲取資料倉儲工具的範例
String desc = "資料倉儲中儲存的資訊如下:";
desc = String.format("%s\n %s為%s", desc, "姓名",
datastore.getStringValue("name"));
desc = String.format("%s\n %s為%d", desc, "年齡",
datastore.getIntValue("age"));
desc = String.format("%s\n %s為%d", desc, "身高",
datastore.getIntValue("height"));
desc = String.format("%s\n %s為%.2f", desc, "體重",
datastore.getDoubleValue("weight"));
desc = String.format("%s\n %s為%b", desc, "婚否",
datastore.getBooleanValue("married"));
desc = String.format("%s\n %s為%s", desc, "更新時間",
datastore.getStringValue("update_time"));
tv_data.setText(desc);
}
從資料倉儲獲取資料的程式碼範例如下:
DatastoreUtil datastore = DatastoreUtil.getInstance(this); // 獲取資料倉儲工具的範例
datastore.setStringValue("name", name); // 新增一個名叫name的字串
datastore.setIntValue("age", Integer.parseInt(age)); // 新增一個名叫age的整數
datastore.setIntValue("height", Integer.parseInt(height)); // 新增一個名叫height的整數
datastore.setDoubleValue("weight", Double.parseDouble(weight)); // 新增一個名叫weight的雙精度數
datastore.setBooleanValue("married", isMarried); // 新增一個名叫married的布林值
datastore.setStringValue("update_time", DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss"));
執行測試App,先開啟記錄儲存頁面,填寫資料後點選儲存按鈕,此時儲存介面如下圖所示。
然後開啟記錄獲取介面,看到記錄獲取結果如下圖所示,說明成功實現了資料倉儲的讀寫功能。