關于作者:CSDN內容合伙人、技術專家, 從零開始做日活千萬級APP。
專注于分享各領域原創系列文章 ,擅長java后端、移動開發、人工智能等,希望大家多多支持。
目錄
- 一、導讀
- 二、概覽
- 三、使用
- 3.1 Preferences DataStore
- 添加依賴
- 數據讀寫
- 3.2 ProtoDataStore
- 添加依賴
- 數據讀寫
- 3.3、在同步代碼中使用 DataStore
- 3.4、在多進程代碼中使用 DataStore
- 四、DataStore & MMKV
- 五、 推薦閱讀
一、導讀
我們繼續總結學習Java基礎知識,溫故知新。
二、概覽
DataStore 是一種用于 Android 應用程序數據存儲的新的推薦方式。
它是在 Android Jetpack 組件中引入的,旨在替代 SharedPreferences,并提供更強大、易于使用的 API。
DataStore 基于 Kotlin 協程和 Flow 構建而成, 提供了一種類型安全且異步的數據存儲解決方案。
相比于 SharedPreferences,DataStore 具有以下優點:
-
異步操作:DataStore 提供了異步的讀寫操作,避免了阻塞主線程的問題。這使得在讀取和寫入數據時,應用程序可以更好地保持響應性能。
-
類型安全:DataStore 支持使用協議緩沖區(Protocol Buffers)來定義數據模型,這樣可以確保在編譯時進行類型檢查。數據模型的更改不會導致運行時錯誤,而是在編譯時進行檢測。
-
支持多種數據類型:DataStore 支持存儲不同類型的數據,包括原始類型、對象或自定義類。
-
數據一致性:DataStore 提供了一致性和安全性保證,保證在多個寫入操作中的數據一致性。
-
流式數據訪問:DataStore 支持使用流(Flow)來訪問數據,使得可以輕松地觀察數據的變化并進行相應的更新。
DataStore 提供了兩個主要的實現方式:PreferencesDataStore 和 ProtoDataStore。
PreferencesDataStore 適用于存儲簡單的數據類型,使用鍵值對來存儲數據。
ProtoDataStore 則使用 Protocol Buffers 定義數據模型,并支持存儲更復雜的數據結構(類型化對象)。
三、使用
3.1 Preferences DataStore
適用于存儲簡單的數據類型,使用鍵值對來存儲數據
添加依賴
// Preferences DataStore (SharedPreferences like APIs)dependencies {implementation "androidx.datastore:datastore-preferences:1.0.0"// optional - RxJava2 supportimplementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"// optional - RxJava3 supportimplementation "androidx.datastore:datastore-preferences-rxjava3:1.0.0"}// Alternatively - use the following artifact without an Android dependency.dependencies {implementation "androidx.datastore:datastore-preferences-core:1.0.0"}
數據讀寫
RxDataStore<Preferences> dataStore =new RxPreferenceDataStoreBuilder(context, /*name=*/ "settings").build();Preferences.Key<Integer> EXAMPLE_COUNTER = PreferencesKeys.int("example_counter");Flowable<Integer> exampleCounterFlow = dataStore.data().map(prefs -> prefs.get(EXAMPLE_COUNTER));Single<Preferences> updateResult = dataStore.updateDataAsync(prefsIn -> {MutablePreferences mutablePreferences = prefsIn.toMutablePreferences();Integer currentInt = prefsIn.get(INTEGER_KEY);mutablePreferences.set(INTEGER_KEY, currentInt != null ? currentInt + 1 : 1);return Single.just(mutablePreferences);
});
// The update is completed once updateResult is completed.
3.2 ProtoDataStore
使用 Protocol Buffers 定義數據模型,并支持存儲更復雜的數據結構
添加依賴
// Typed DataStore (Typed API surface, such as Proto)dependencies {implementation "androidx.datastore:datastore:1.0.0"// optional - RxJava2 supportimplementation "androidx.datastore:datastore-rxjava2:1.0.0"// optional - RxJava3 supportimplementation "androidx.datastore:datastore-rxjava3:1.0.0"}// Alternatively - use the following artifact without an Android dependency.dependencies {implementation "androidx.datastore:datastore-core:1.0.0"}
數據讀寫
Proto DataStore 要求在 app/src/main/proto/ 目錄的 proto 文件中保存預定義的架構。
此架構用于定義在 Proto DataStore 中保存的對象的類型。
syntax = "proto3";option java_package = "com.example.application";
option java_multiple_files = true;message Settings {int32 example_counter = 1;
}
private static class SettingsSerializer implements Serializer<Settings> {@Overridepublic Settings getDefaultValue() {Settings.getDefaultInstance();}@Overridepublic Settings readFrom(@NotNull InputStream input) {try {return Settings.parseFrom(input);} catch (exception: InvalidProtocolBufferException) {throw CorruptionException(“Cannot read proto.”, exception);}}@Overridepublic void writeTo(Settings t, @NotNull OutputStream output) {t.writeTo(output);}
}RxDataStore<Byte> dataStore =new RxDataStoreBuilder<Byte>(context, /* fileName= */ "settings.pb", new SettingsSerializer()).build();Flowable<Integer> exampleCounterFlow =dataStore.data().map(settings -> settings.getExampleCounter());Single<Settings> updateResult = dataStore.updateDataAsync(currentSettings ->Single.just(currentSettings.toBuilder().setExampleCounter(currentSettings.getExampleCounter() + 1).build()));
3.3、在同步代碼中使用 DataStore
DataStore 的主要優勢之一是異步 API,但可能不一定始終能將周圍的代碼更改為異步代碼。如果您使用的現有代碼庫采用同步磁盤 I/O,或者您的依賴項不提供異步 API,就可能出現這種情況。
Kotlin 協程提供 runBlocking() 協程構建器,以幫助消除同步與異步代碼之間的差異。您可以使用 runBlocking() 從 DataStore 同步讀取數據。RxJava 在 Flowable 上提供阻塞方法。以下代碼會阻塞發起調用的線程,直到 DataStore 返回數據:
Settings settings = dataStore.data().blockingFirst();dataStore.data().first().subscribe();
這樣,DataStore 可以異步讀取數據并將其緩存在內存中。以后使用 runBlocking() 進行同步讀取的速度可能會更快,或者如果初始讀取已經完成,可能也可以完全避免磁盤 I/O 操作。
- 請盡可能避免在 DataStore 數據讀取時阻塞線程。阻塞界面線程可能會導致 ANR 或界面卡頓,而阻塞其他線程可能會導致死鎖。
3.4、在多進程代碼中使用 DataStore
- DataStore 多進程功能目前僅在 1.1.0 Alpha 版中提供
為了能夠在不同進程中使用 DataStore,需要使用 MultiProcessDataStoreFactory 構造 DataStore 對象。
val dataStore: DataStore<Settings> = MultiProcessDataStoreFactory.create(serializer = SettingsSerializer(),produceFile = {File("${context.cacheDir.path}/myapp.preferences_pb")}
)
四、DataStore & MMKV
看一組數據對比,圖片來源于MMKV 開源網站
至于如何使用就不描述了,非常簡單。
個人感覺 DataStore 沒有 MMKV 好用,推薦使用 MMKV,但是各有優劣吧。
jetpack 官網
datastore
五、 推薦閱讀
Java 專欄
SQL 專欄
數據結構與算法
Android學習專欄