Jetpack DataStore:Android应用中的现代数据存储方法
目次
在学习 DataStore 之前,需要先了解 Kotlin 属性委托 的概念。
Kotlin 属性委托简介 #
Kotlin 支持通过 属性委托 (by
) 来委托属性的获取和设置逻辑。
基本规则是:如果一个对象实现了如下方法:
|
|
那么就可以用 by 实例
的方式将属性委托给该对象。
示例:
|
|
上面的写法将 DataStore 实例绑定到 Context
的扩展属性 dataStore
,访问时会通过委托自动初始化。
创建 DataStore 实例 #
|
|
preferencesDataStore
方法利用 Kotlin 的属性委托创建 DataStore,并通过 double-check 机制 确保整个应用中访问到的都是同一个实例。
DataStore 是一个数据接口,它主要有两种实现:
- Preference DataStore:对应 SharedPreferences 风格,使用键值对存储。
- Proto DataStore:对应 ProtoBuf 协议,存储自定义类型,需要手动实现序列化和反序列化。
DataStore 内部关键组件 #
DataStoreImpl
是 DataStore 的核心实现类,其中关键变量有:
inMemoryCache: DataStoreInMemoryCache<T>
- 存储状态数据,Flow 中的 T 是
State<T>
,可直接拿到当前状态。
- 存储状态数据,Flow 中的 T 是
readAndInit: InitDataStore()
- 负责初始化和读取文件,将
UnInitialized
状态更新为Data
状态。
- 负责初始化和读取文件,将
coordinator: SingleProcessCoordinator
- 单进程场景下用于版本控制和锁管理,保证数据一致性。
DataStore 状态 #
DataStore 内部状态包括:
UnInitialized
:初始状态,需要解析文件。Data
:数据已初始化,可正常读取。ReadException
:读取失败。Final
:最终状态,缓存数据不再更新。
第一次访问 DataStore 时,状态为 UnInitialized
,初始化完成后才会切换到 Data
状态。
|
|
readAndInit
的核心逻辑是 只执行一次:
|
|
通过 didRun.isCompleted
判断是否已经初始化,保证首次初始化只执行一次。
读取数据流程 #
- 首次读取会调用
readAndInit.runIfNeeded()
解析文件。 - 初始化完成后,后续读取会直接从
inMemoryCache
获取数据。 - 读取操作是异步的,结合 Flow 可以实现响应式数据更新。
|
|
写入数据流程 #
写入流程与 SharedPreferences 类似,但更加安全和异步:
|
|
DataStore 写入特点:
- 数据先更新到内存缓存。
- 再写入临时文件(.tmp)。
- 临时文件写入成功后,覆盖原文件。
- 通过版本号和锁机制保证多线程/多进程访问一致性。
示例核心实现:
|
|
DataStore 与 SharedPreferences 对比 #
特性 | SharedPreferences | DataStore |
---|---|---|
存储方式 | XML 文件 | Proto / Preferences Map |
初始化 | 同步解析 XML,可能导致 ANR | 异步解析,基于 Flow |
写入 | onPause/onStop 阻塞磁盘写入 | 先写 tmp 文件,再覆盖,异步安全 |
多线程/多进程 | 支持有限,多线程容易出错 | 通过锁和版本号保证一致性 |
类型安全 | 仅基本类型 | Preferences 无类型安全,Proto 可自定义类型 |
Proto DataStore #
Proto DataStore 使用 Protobuf 存储数据:
- 类型由外部定义,DataStore 不解析具体格式。
- 需要实现序列化和反序列化逻辑。
- 上层使用方式与 Preference DataStore 类似,但底层存储格式为 Proto。
多进程支持 #
DataStore 支持多进程访问,区别在于锁机制:
- 单进程使用
Mutex
。 - 多进程使用
fcntl
文件锁,对整个文件加锁,保证跨进程数据一致性。
|
|
总结 #
DataStore 相比 SharedPreferences 的优势:
- 异步、安全,避免 ANR。
- 先写入临时文件,再覆盖原文件,保证数据一致性。
- 支持 Flow,实现响应式数据更新。
- 通过版本号和锁机制,支持多线程与多进程安全。
- 支持 Proto 格式,类型安全可扩展。
参考资料 #
Categories: