1. 为什么选择DataStore?
1.1 背景
在Android开发中,SharedPreferences
一直是轻量级存储键值对的常用工具。然而,随着应用的复杂性增加,SharedPreferences
的一些局限性逐渐显现:
- 性能问题:在主线程进行 I/O 操作,可能导致 UI 卡顿。
- 缺乏类型安全:需要手动进行类型转换,容易出错。
- 事务冲突:多个线程同时写入时可能出现数据覆盖问题。
- 同步问题:
apply()
方法是异步的,不能保证数据立即持久化。
为了解决这些问题,Google 在 Jetpack 中引入了 DataStore,它采用了更现代化的设计,提供了更高效和安全的数据存储方案。
1.2 DataStore 的特点
- 异步非阻塞:基于 Kotlin 协程,所有操作均为异步,避免阻塞主线程。
- 类型安全:支持
Preferences DataStore
和Proto DataStore
两种类型,后者提供了更严格的类型检查。 - 更好的性能:基于文件流的底层实现,比
SharedPreferences
更高效。
2. DataStore 的两种类型
2.1 Preferences DataStore
存储键值对数据,类似于 SharedPreferences
。适用于简单的数据存储场景。
2.2 Proto DataStore
基于 Protocol Buffers(Protobuf),用于存储结构化数据。适合需要严格类型的数据模型。
3. 与 SharedPreferences 的区别
特性 | SharedPreferences | DataStore |
---|---|---|
存储方式 | 基于 XML 文件 | 基于文件流 |
异步支持 | 不完全异步,apply 异步,commit 同步 | 完全异步 |
线程安全 | 存在并发问题 | 原生线程安全 |
类型安全 | 不支持,需要手动管理 | Proto DataStore 支持严格类型安全 |
性能 | 主线程阻塞风险 | 高效,非阻塞 |
4. 如何使用 DataStore
4.1 添加依赖
在 build.gradle
文件中添加:
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.datastore:datastore-core:1.0.0"
4.2 Preferences DataStore 示例
4.2.1 初始化 DataStore
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
4.2.2 写入数据
suspend fun saveSetting(context: Context, key: String, value: Int) {
val dataStoreKey = intPreferencesKey(key)
context.dataStore.edit { settings ->
settings[dataStoreKey] = value
}
}
4.2.3 读取数据
val exampleFlow: Flow<Int> = context.dataStore.data
.map { preferences ->
preferences[intPreferencesKey("example_key")] ?: 0
}
4.3 Proto DataStore 示例
4.3.1 定义 Protobuf 文件
创建 settings.proto
文件:
syntax = "proto3";
option java_package = "com.example.datastore";
option java_outer_classname = "SettingsProto";
message Settings {
int32 example_value = 1;
}
编译生成对应的类文件。
4.3.2 初始化 Proto DataStore
val Context.protoDataStore: DataStore<Settings> by dataStore(
fileName = "settings.pb",
serializer = SettingsSerializer
)
4.3.3 创建序列化器
object SettingsSerializer : Serializer<Settings> {
override val defaultValue: Settings = Settings.getDefaultInstance()
override suspend fun readFrom(input: InputStream): Settings {
return try {
Settings.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
defaultValue
}
}
override suspend fun writeTo(t: Settings, output: OutputStream) {
t.writeTo(output)
}
}
4.3.4 写入数据
suspend fun updateExampleValue(context: Context, value: Int) {
context.protoDataStore.updateData { settings ->
settings.toBuilder().setExampleValue(value).build()
}
}
4.3.5 读取数据
val exampleValueFlow: Flow<Int> = context.protoDataStore.data
.map { settings ->
settings.exampleValue
}
5. 图解 DataStore 工作原理
6. 总结
DataStore 是 Android 平台上对标 SharedPreferences
的现代化存储解决方案。通过支持异步、类型安全和更高效的底层实现,DataStore 提供了一种更适合现代应用的数据存储方式。开发者可以根据具体需求选择 Preferences DataStore
或 Proto DataStore
来满足应用需求。