1. 认识 DataStore:用途、两种实现与适用场景
Jetpack DataStore 是 Android 官方推出的轻量级本地数据存储解决方案,旨在替代 SharedPreferences,提供异步、一致且类型安全的键值存储与结构化数据持久化能力。它基于 Kotlin 协程和 Flow(数据流)构建,天然支持反应式编程与生命周期安全。
1.1 核心用途
- 持久化应用设置与偏好:如主题、语言、通知开关等轻度用户配置。
- 小型结构化数据缓存:如最近使用的项目列表、登录状态标志。
- 单进程内数据共享:同一 App 内多个组件通过 Flow 观察数据变化,实现实时同步。
- 替代 SharedPreferences 线程安全与异常问题:DataStore 确保主线程安全,并支持
try-catch处理序列化/反序列化异常。
1.2 原理概述
DataStore 以文件形式将数据持久化到设备内部存储。读取时返回 Flow<T>,数据变更时会自动发射新值;写入操作通过挂起函数 updateData() 或 edit() 实现事务性修改。整个读写过程由协程调度,避免阻塞主线程。
1.3 两种实现对比
| 特性 | Preferences DataStore | Proto DataStore |
|---|---|---|
| 数据结构 | 键-值对(Key-Value),值类型固定(Int、String、Boolean、Float、Double、StringSet 等) | 基于 Protocol Buffers(protobuf)定义的结构化对象,支持嵌套、枚举、自定义类型 |
| 类型安全 | 弱类型,需在存取时手动转换 | 强类型,编译期生成 Java/Kotlin 类 |
| Schema 演进 | 无 schema,字段增删需手动处理默认值 | 支持向后兼容,proto 文件定义字段编号,可安全新增/废弃字段 |
| 依赖体积 | 小,仅需 datastore-preferences | 较大,需引入 datastore 和 protobuf 插件 |
| 适用场景 | 简单设置项、开关、计数器 | 复杂配置对象、网络缓存模型、数据迁移 |
| 读写性能 | 写入快(全量替换),但读取全部数据后过滤 | 写入稍慢(序列化成本),读取按需反序列化字段 |
选择建议:Preferences DataStore 适合 少于 20 个键 的纯设置场景;Proto DataStore 适合 结构化、版本可演进 的数据模型。
1.4 适用场景决策流程
1.5 依赖引入与基础配置
在 build.gradle.kts(模块级)添加对应依赖:
// Preferences DataStore
implementation("androidx.datastore:datastore-preferences:1.1.1")
// Proto DataStore(需要额外配置 protobuf 插件)
implementation("androidx.datastore:datastore:1.1.1")
// 还需要在 build.gradle.kts 中配置 protobuf 插件和定义 .proto 文件
⚠ 版本兼容提示:DataStore 1.1.x 要求 Kotlin 1.8+ 以及 compileSdk 33+。若使用更低版本,请查阅官方迁移指南。
1.6 常见错误与稳定性优化
- 在非协程作用域调用写入方法:必须处于协程上下文中,否则编译报错。
- 文件损坏导致读取异常:DataStore 内部使用事务日志,但极端情况仍可抛出
CorruptionException,建议在外层catch后重建。 - 跨进程共享不可靠:DataStore 本身不支持多进程并发,需要跨进程应在 ContentProvider 或自定义 Service 中封装。
- 高频写操作合并:DataStore 会合并 5 秒内的连续写入为一次磁盘操作,避免频繁 I/O 抖动。
- 使用
dataStore.data的 collect 时注意取消:配合repeatOnLifecycle或flowWithLifecycle防止生命周期泄露。
性能要点:首次读 DataStore 时会从文件加载全部数据到内存缓存,后续读取仅返回缓存;写入时先更新缓存再异步写回文件。保持每个 DataStore 实例管理的数据量在 100KB 以内可达到最佳性能。