Jetpack DataStore 你总要了解一下吧?
一、DataStore 介绍
DataStore 是 Android Jetpack 中的一个组件,它是一个数据存储的解决方案,跟 SharedPreferences 一样,采用key-value形式存储。DataStore 保证原子性,一致性,隔离性,持久性。尤其是,它解决了 SharedPreferences API 的设计缺陷。Jetpack DataStore 是经过改进的新版数据存储解决方案,旨在取代 SharedPreferences,让应用能够以异步、事务方式存储数据。
注意:DataStore 比较适合小数据和简单操作,并且无法局部的更新数据。如果你需要支持大型或复杂的数据集、部分更新或引用完整性,请考虑使用 Room 而不是 DataStore。
Preferences DataStore 和 Proto DataStore
-
Preferences DataStore:与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。 -
Proto DataStore:通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。
本文重点了解Preferences DataStore。
二、Preferences DataStore
与SharedPreferences类似,通过键值对存储数据,此实现不需要预定义模式,也不提供类型安全。
2.1 添加依赖
在你项目的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"
}
2.2 使用 Preferences DataStore 存储键值对
首先看看 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 那是相当执着。
2.2.1 创建 DataStore
-
使用 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 类型。
2.2.1 DataStore 写入数据
//关于 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 比较少实践少就不提供工具类了,以免误导大家。
2.2.3 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());
}
三、Proto DataStore
通过Protocol-Buffers定义存储数据类型以及结构,保证类型安全。
Proto DataStore 实现使用 DataStore 和 Protocol-Buffers 将类型化对象持久保存到磁盘。
什么是 Protocol-Buffers?
Protocol-Buffers是谷歌的语言中立、平台中立、可扩展的机制,用于序列化结构化数据——比如XML,但更小、更快、更简单。您只需定义一次数据的结构化方式,然后就可以使用特殊生成的源代码,轻松地在各种数据流之间以及使用各种语言编写和读取结构化数据。
3.1 定义架构
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 你的项目。
3.2 创建 Proto DataStore
-
1.定义一个实现 Serializer<T>
的类,其中 T 是 proto 文件中定义的类型。 -
2.使用 dataStore 创建的属性委托来创建 DataStore<T>
的实例,其中 T 是 proto 文件中定义的类型。
写到这里 proto 文件中定义的类无法生成,也尝试了很多办法,不知道什么情况。后续步骤可参照官网,其他方法和Preferences DataStore类似。就不占用篇幅了。
相关链接
个人感觉 DataStore 还是没有 SP 和 MMKV 好用,推荐使用 MMKV 毕竟上线好几年了,而且是大厂推出,相对稳定一些,有些个人自己实现了 SP 的功能,但是万一有 Bug 或者突然不继续维护了是不是就尴尬了。
- 点赞
- 收藏
- 关注作者
评论(0)