Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。
DataStore 提供两种不同的实现:Preferences DataStore 和 Proto DataStore。
DataStore 官方文档
Proto3 语法入门
Proto3 官方语法指南
SharedPreference(简称SP) 是一个轻量级的数据存储方式,使用方便,以键值对的形式存储在本地。
SP的缺点:
DataStore优点:
project/build.gradle
buildscript {
dependencies {
// Proto DataStore
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.19'
}
}
module/build.gradle
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.protobuf'
}
dependencies {
// Preferences DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.datastore:datastore-core:1.0.0"
// Proto DataStore
implementation 'androidx.datastore:datastore-core:1.0.0'
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.0"
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.14.0"
}
// 为该项目中的 Protobufs 生成 java Protobuf-lite 代码。
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
}
}
}
}
}
DataStore 生成的缓存文件存放在 /data/data/<包名>/files/datastore
目录下:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_info")
lifecycleScope.launch {
dataStore.edit { preferences ->
// 先通过 stringPreferencesKey() 方法获取指定Key
val nameKey = stringPreferencesKey("name")
val ageKey = intPreferencesKey("age")
val sexKey = booleanPreferencesKey("sex")
// 通过Key获取值
val name = preferences[nameKey]
val age = preferences[ageKey]
val sex = preferences[sexKey]
logE("name:$name age:$age sex:$sex")
}
}
dataStore.edit { preferences ->
preferences[stringPreferencesKey("name")] = "小明"
preferences[intPreferencesKey("age")] = 18
preferences[booleanPreferencesKey("sex")] = true
}
dataStore.edit { preferences ->
preferences[stringPreferencesKey("name")] = "小黑"
preferences[intPreferencesKey("age")] = 28
preferences[booleanPreferencesKey("sex")] = false
}
dataStore.edit { preferences ->
val removeValue = preferences.remove(stringPreferencesKey("name"))
logE("remove:$removeValue")
}
dataStore.edit { preferences ->
preferences.clear()
}
先新建 proto 目录:
再创建 person.proto 文件,并写入:
syntax = "proto3";
option java_package = "com.example.datastoredemo"; //设置生成的类所在的包
option java_multiple_files = true; //可能会有多个文件。
message PersonPreferences {
string name = 1; //String类型
int32 age = 2; //int类型
bool sex = 3; //boolean类型
repeated string address = 4; //String[]数组
map fruits = 5; //Map类型
}
object PersonSerializer : Serializer<PersonPreferences> {
override val defaultValue: PersonPreferences
get() = PersonPreferences.getDefaultInstance()
override suspend fun writeTo(t: PersonPreferences, output: OutputStream) {
t.writeTo(output)
}
override suspend fun readFrom(input: InputStream): PersonPreferences {
try {
return PersonPreferences.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", exception)
}
}
}
val Context.personDataStore: DataStore<PersonPreferences> by dataStore(
fileName = "person.pb", serializer = PersonSerializer
)
lifecycleScope.launch {
personDataStore.data.first().let { preferences ->
val name = preferences.name
val age = preferences.age
val sex = preferences.sex
val address = preferences.addressList
val fruits = preferences.fruitsMap
logE("name:$name age:$age sex:$sex address:$address fruits:$fruits")
}
}
preferences.toBuilder()
.setName("小白")
.setAge(28)
.setSex(true)
.addAddress("广东省")
.addAddress("广州市")
.addAddress("黄埔区")
.putFruits("apple", "苹果")
.putFruits("banner", "香蕉")
.putFruits("cherry", "樱桃")
.build()
preferences.toBuilder()
.setName("小白")
.setAge(28)
.setSex(true)
.addAllAddress(listOf("广东省", "广州市", "黄埔区"))
.putAllFruits(mapOf("apple" to "苹果", "banner" to "香蕉", "cherry" to "樱桃"))
.build()
personDataStore.updateData { preferences -
preferences.toBuilder()
.setName("小黑")
.setAge(38)
.setSex(false)
.setAddress(0, "湖南省")
.setAddress(1, "长沙市")
.setAddress(2, "芙蓉区")
.putFruits("apple", "苹果1号")
.build()
}
personDataStore.updateData { preferences ->
preferences.toBuilder()
.removeFruits("apple") // 删除map数据
.build()
}
personDataStore.updateData { preferences ->
// 清除所有数据
preferences.toBuilder()
.clear()
.build()
// 依次清除数据
preferences.toBuilder()
.clearName()
.clearAge()
.clearSex()
.clearAddress()
.clearFruits()
.build()
}
personDataStore.updateData { preferences ->
// 清除所有数据
preferences.toBuilder()
.clear()
.build()
// 依次清除数据
preferences.toBuilder()
.clearName()
.clearAge()
.clearSex()
.clearAddress()
.clearFruits()
.build()
}