Jetpack DataStore是一个基于Android平台的本地数据存储解决方案,它使用Kotlin协程和Flow以异步、一致的事务方式存储数据,并且提供了两种实现,一种是Proto DataStore,使用protocol buffers协议序列化存储和访问对象,另外一种是Preferences DataStore,使用键值对的方式存储访问。它弥补了SharedPreferences的很多不足,下面是两者之间的区别:
SharedPreferences提供了同步的API来读取数据,虽然可以在UI线程中调用,但实际上它调用了IO操作,另外apply()虽然是异步进行IO操作,但是它也有可能会阻塞UI线程,但是在Service和Activity组件的onStart和onStop生命周期方法调用时,会去等待上面的IO操作完成再继续运行,如果上面的异步IO操作没有完成的话就会造成UI线程卡顿,甚至ANR。
DataStore的两种实现,除非特殊指定,处理操作和IO操作都是在Dispatchers.IO中完成。Proto DataStore和Preference DataStore的区别如下:
DataStore和Room对比
和Room比起来,DataStore更适合存储较小的数据,另外DataStore不支持部分更新,只能完整更新,如果需要支持部分更新或者数据量比较大,请选择Room,DataStore相比Room的优势是使用简单。
首先在build.gradle中添加DataStore的依赖,如果使用Datastore Preferences,依赖如下:
//Preferences DataStore
dependencies {
implementation "androidx.datastore:datastore-preferences:1.0.0"
// 可选 - 支持RxJava2
implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"
// 可选 - 支持RxJava3
implementation "androidx.datastore:datastore-preferences-rxjava3:1.0.0"
}
如果是Proto DataStore,依赖如下:
// Proto DataStore (Typed API surface, such as Proto)
dependencies {
implementation "androidx.datastore:datastore:1.0.0"
// 可选 - 支持RxJava2
implementation "androidx.datastore:datastore-rxjava2:1.0.0"
// 可选 - 支持RxJava3
implementation "androidx.datastore:datastore-rxjava3:1.0.0"
}
1//使用preferencesDataStore创建的属性委托来创建DataStore
2val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
3
4//读取一个int类型数据,key是counter
5val counter = intPreferencesKey("counter")
6val counterFlow: Flow<Int> = context.dataStore.data
7 .map { preferences ->
8 preferences[counter] ?: 0
9}
10
11//写入数据,以事物方式更新数据,edit内部代码块视为单个事物
12context.dataStore.edit { preferences ->
13 val current = preferences[counter] ?: 0
14 preferences[counter] = current + 1
15}
在使用Proto DataStore之前,需要在app/src/main/proto/
目录下为序列化对象定义proto文件,定义好后编译项目,编译器会自动根据proto文件生成Java类。
syntax = "proto3";
option java_package = "com.example.datastore";
option java_multiple_files = true;
message User {
int32 id = 1;
string name = 2;
}
然后定义好序列接口并创建DataStore进行操作
1//定义序列接口
2object UserSerializer : Serializer<User> {
3 override val defaultValue: User = User.getDefaultInstance()
4
5 override suspend fun readFrom(input: InputStream): User = User.parseFrom(input)
6
7 override suspend fun writeTo(t: User, output: OutputStream) = t.writeTo(output)
8}
9
10//创建Proto DataStore
11val Context.userDataStore: DataStore<User> by dataStore(
12 fileName = "user.pb",
13 serializer = UserSerializer
14)
15
16//读取数据
17val userFlow: Flow<User> = userDataStore.data.map { user ->
18 user
19}
20
21//写入数据
22userDataStore.updateData { current ->
23 current.toBuilder()
24 .setId(current.id + 1)
25 .setName(UUID.randomUUID().toString())
26 .build()
27}
下面是一个包含Preferences DataStore和Proto DataStore使用的简单示例。
val dataStore: DataStore<Preferences> = context.createDataStore(
name = "settings",
migrations = listOf(SharedPreferencesMigration(context, "settings_preferences"))
)
1val settingsDataStore: DataStore<Settings> = context.createDataStore(
2 produceFile = { File(context.filesDir, "settings.preferences_pb") },
3 serializer = SettingsSerializer,
4 migrations = listOf(
5 SharedPreferencesMigration(
6 context,
7 "settings_preferences"
8 ) { sharedPrefs: SharedPreferencesView, currentData: UserPreferences ->
9 //实现转换方法
10 }
11 )
12)