赞
踩
目录
Preferences DataStore 和 Proto DataStore
2.2 使用 Preferences DataStore 存储键值对
DataStore 是 Android Jetpack 中的一个组件,它是一个数据存储的解决方案,跟 SharedPreferences 一样,采用key-value形式存储。
DataStore 保证原子性,一致性,隔离性,持久性。尤其是,它解决了 SharedPreferences API 的设计缺陷。
Jetpack DataStore 是经过改进的新版数据存储解决方案,旨在取代 SharedPreferences,让应用能够以异步、事务方式存储数据。
注意:DataStore 比较适合小数据和简单操作,并且无法局部的更新数据。如果你需要支持大型或复杂的数据集、部分更新或引用完整性,请考虑使用 Room 而不是 DataStore。
Preferences DataStore:与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。
Proto DataStore:通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。
本文重点了解Preferences DataStore。
与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。
在你项目的app_module对应的build.gradle中添加如下依赖:
- dependencies {
- //Typed DataStore (Typed API surface, such as Proto)
- implementation "androidx.datastore:datastore:1.0.0"
- // //可选 - RxJava2 support
- // implementation "androidx.datastore:datastore-rxjava2:1.0.0"
- // //可选 - RxJava3 support
- implementation "androidx.datastore:datastore-rxjava3:1.0.0"
-
- //Preferences DataStore (SharedPreferences like APIs)
- implementation "androidx.datastore:datastore-preferences:1.0.0"
- // // 可选 - RxJava2 support
- // implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"
- // // 可选 - RxJava3 support
- implementation "androidx.datastore:datastore-preferences-rxjava3:1.0.0"
- }
首先看看 DataStore 源码,DataStore 是一个接口。
- package androidx.datastore.core
-
- import kotlinx.coroutines.flow.Flow
- import java.io.IOException
-
- /**
- * DataStore数据存储提供了一种安全、持久的方式来存储少量数据,如 preferences 和应用程序状态。
- * 数据存储提供了ACID保证。它是线程安全的,并且不阻塞。特别是,它解决了SharedReferences API的这些设计缺陷:
- * 1. Synchronous API encourages StrictMode violations
- * 2. apply() and commit() have no mechanism of signalling errors
- * 3. apply() will block the UI thread on fsync()
- * 4. Not durable – it can returns state that is not yet persisted
- * 5. No consistency or transactional semantics
- * 6. Throws runtime exception on parsing errors
- * 7. Exposes mutable references to its internal state
- */
- public interface DataStore<T> {
- public val data: Flow<T>
-
- public suspend fun updateData(transform: suspend (t: T) -> T): T
- }

以上可以看出 DataStore 是基于 协程 和 Flow 实现的。
data 是一个 Flow 对象。
updateData() 用于更新对象。
并且查看 DataStore 的其他相关源码你会发现他们都是基于Kotlin语言开发。Google 对于推 Kotlin 那是相当执着。
使用 preferencesDataStore(Kotlin) 创建Datastore<Preferences>
的实例。
如果你使用 RxJava,要使用 RxPreferenceDataStoreBuilder。
必需的 name 参数是 Preferences DataStore 的名称。
这里我们使用的是RxJava:
- RxDataStore<Preferences> dataStore =
- new RxPreferenceDataStoreBuilder(this, /*name=*/ "datastore_sc").build();
- //创建使用的key
- Preferences.Key<String> nameKey = PreferencesKeys.stringKey("name");
- Preferences.Key<Integer> ageKey = PreferencesKeys.intKey("age");
默认路径:/data/data/com.scc.datastorage/files/datastore/datastore_sc.preferences_pb
这里创建了两个key,分别是 String 类型和 Int 类型。
- //关于 nameKey 和 ageKey 请看上面代码。
- putString(nameKey, "name-Scc");
- putInteger(ageKey, 25);
-
- //2022/1/25 功能:存入String类型的数据
- private void putString(Preferences.Key<String> nameKey, String value) {
- dataStore.updateDataAsync(new Function<Preferences, Single<Preferences>>() {
- @Override
- public Single<Preferences> apply(Preferences preferences) throws Throwable {
- MutablePreferences mutablePreferences = preferences.toMutablePreferences();
- mutablePreferences.set(nameKey, value);
- return Single.just(mutablePreferences);
- }
- });
- }
- //2022/1/25 功能:存入Integer类型的数据
- private void putInteger(Preferences.Key<Integer> ageKey, Integer value) {
- dataStore.updateDataAsync(new Function<Preferences, Single<Preferences>>() {
- @Override
- public Single<Preferences> apply(Preferences preferences) throws Throwable {
- MutablePreferences mutablePreferences = preferences.toMutablePreferences();
- mutablePreferences.set(ageKey, value);
- return Single.just(mutablePreferences);
- }
- });
- }

这里写入的两种类型,这样更加仿版理解和你写成自己的工具类,因为使用 DataStore 比较少实践少就不提供工具类了,以免误导大家。
- getString(nameKey);
- getInteger(ageKey);
-
- //2022/1/25 功能:获取String类型数据
- private void getString(Preferences.Key<String> nameKey) {
- Log.e("DataStore", nameKey.toString());
- Flowable<String> example = dataStore.data().map(new Function<Preferences, String>() {
- @Override
- public String apply(Preferences preferences) {
- Log.e("DataStore.apply", preferences.get(nameKey));
- return preferences.get(nameKey);
- }
- });
- Log.e("DataStore.Flowable", example.first("default").blockingGet());
- }
- //2022/1/25 功能:获取Integer类型数据
- private void getInteger(Preferences.Key<Integer> ageKey) {
- Log.e("DataStoreKey", ageKey.toString());
- Flowable<Integer> example = dataStore.data().map(new Function<Preferences, Integer>() {
- @Override
- public Integer apply(Preferences preferences) {
- Log.e("DataStore.apply", preferences.get(ageKey).intValue() + "");
- return preferences.get(ageKey);
- }
- });
- Log.e("DataStore.Flowable", example.first(12).blockingGet().toString());
- }

通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。
Proto DataStore 实现使用 DataStore 和 Protocol-Buffers 将类型化对象持久保存到磁盘。
什么是 Protocol-Buffers?
Protocol-Buffers是谷歌的语言中立、平台中立、可扩展的机制,用于序列化结构化数据——比如XML,但更小、更快、更简单。您只需定义一次数据的结构化方式,然后就可以使用特殊生成的源代码,轻松地在各种数据流之间以及使用各种语言编写和读取结构化数据。
Proto DataStore 需要app/src/main/proto/目录中的 proto 文件中的预定义模式。此架构定义了您在 Proto DataStore 中持久保存的对象的类型。
- syntax = "proto3";
- option java_multiple_files = true;
- option java_package = "com.scc.datastorage.proto";
- option java_outer_classname = "User";
-
- message User{
- string name = 1;
- int32 age = 2;
- }
.proto 文件以包声明开头,这有助于防止不同项目之间的命名冲突。
java_multiple_files:可以为每个生成的类生成一个单独的 .java 文件。
java_package:指定生成的类应该使用什么 Java 包名称。如果您没有明确指定,它只会匹配包声明给出的包名。
java_outer_classname:定义了类名。如果没有设置这个 options ,它将通过将文件名转换为大写驼峰式来生成。例如,默认情况下,“my_proto.proto”将使用“MyProto”作为包装类名称。
定义 message:
可以使用许多标准的简单数据类型可用作字段类型,包括 bool、int32、float、double 和 string。
还可以通过使用其他 message 类型作为字段类型来为你的消息添加进一步的结构。
每个元素上的 "= 1"、"= 2" 标记标识该字段在二进制编码中使用的唯一 "tag"。
更多关于 的内容可以去官网找找 protobuf 语言指南。
注意:存储对象的类是在编译时从 proto 文件中定义的message生成的。确保你 rebuild 你的项目。
1.定义一个实现 Serializer<T>
的类,其中 T 是 proto 文件中定义的类型。
2.使用 dataStore 创建的属性委托来创建 DataStore<T>
的实例,其中 T 是 proto 文件中定义的类型。
写到这里 proto 文件中定义的类无法生成,也尝试了很多办法,不知道什么情况。后续步骤可参照官网,其他方法和Preferences DataStore类似。就不占用篇幅了。
个人感觉 DataStore 还没有 SP 和 MMKV 好用,推荐使用 MMKV 毕竟上线好几年了,而且是大厂推出,相对稳定一些,有些个人自己实现了 SP 的功能,但是万一有 Bug 或者突然不继续维护了是不是就尴尬了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。