Android DataStore(Preferences)基本使用教程
1. DataStore 是什么?
DataStore 是 Android 官方提供的数据持久化方案 ,用于存储小规模本地数据 ,
是 SharedPreferences 的推荐替代方案。
核心特性:
- 基于 Kotlin Coroutines + Flow
- 线程安全
- 原子写入
- 支持 数据变化监听
- 官方长期维护
2. DataStore 的两种类型(先分清)
| 类型 | 依赖 | 使用场景 |
|---|---|---|
| Preferences DataStore | androidx.datastore:datastore-preferences |
Key-Value,替代 SharedPreferences |
| Proto DataStore | androidx.datastore:datastore |
强类型对象,复杂数据 |
👉 本文只讲 Preferences DataStore
3. 添加依赖
3.1 使用 Version Catalog(推荐)
toml
[libraries]
androidx-datastore-preferences = {
module = "androidx.datastore:datastore-preferences",
version = "1.1.0"
}
kotlin
implementation(libs.androidx.datastore.preferences)
3.2 直接依赖(不推荐但可用)
kotlin
implementation("androidx.datastore:datastore-preferences:1.1.0")
4. 定义 DataStore(关键)
4.1 在 Context 上定义(必须是单例)
kotlin
val Context.dataStore by preferencesDataStore(
name = "settings"
)
📌 规则:
- 一个文件 = 一个 DataStore
- 不要在多个地方重复定义
- 通常放在
Application或datastore包中
5. 定义 Key(强烈建议集中管理)
kotlin
object PreferenceKeys {
val MUSIC_ID = stringPreferencesKey("music_id")
val POSITION = longPreferencesKey("position")
val IS_PLAYING = booleanPreferencesKey("is_playing")
}
支持的类型:
stringPreferencesKeyintPreferencesKeylongPreferencesKeybooleanPreferencesKeyfloatPreferencesKeystringSetPreferencesKey
6. 写数据(edit)
6.1 基本写法
kotlin
suspend fun saveMusicId(context: Context, id: String) {
context.dataStore.edit { prefs ->
prefs[PreferenceKeys.MUSIC_ID] = id
}
}
特点
edit是 suspend 函数- 自动切换线程(不会阻塞主线程)
- 一次
edit是一个原子事务
6.2 一次写多个值(推荐)
kotlin
context.dataStore.edit { prefs ->
prefs[PreferenceKeys.MUSIC_ID] = "123"
prefs[PreferenceKeys.POSITION] = 1000L
}
✔ 要么全部成功
✔ 要么全部失败
7. 读数据(Flow)
7.1 基本读取
kotlin
val musicIdFlow: Flow<String> =
context.dataStore.data
.map { prefs ->
prefs[PreferenceKeys.MUSIC_ID] ?: ""
}
特点
- 返回的是 Flow
- 数据变化会自动 emit
- 不需要回调
7.2 一次读多个值(推荐)
kotlin
data class PlayerState(
val musicId: String,
val position: Long
)
val playerStateFlow: Flow<PlayerState> =
context.dataStore.data.map { prefs ->
PlayerState(
musicId = prefs[PreferenceKeys.MUSIC_ID] ?: "",
position = prefs[PreferenceKeys.POSITION] ?: 0L
)
}
8. 在 ViewModel 中使用(推荐)
kotlin
class PlayerViewModel(
private val context: Context
) : ViewModel() {
val playerState = context.dataStore.data
.map { prefs ->
prefs[PreferenceKeys.MUSIC_ID] ?: ""
}
}
9. 在 Compose 中使用(最佳实践)
kotlin
@Composable
fun PlayerScreen(viewModel: PlayerViewModel) {
val musicId by viewModel.playerState
.collectAsStateWithLifecycle(initialValue = "")
Text(text = musicId)
}
10. 清除数据
10.1 清空全部
kotlin
context.dataStore.edit { it.clear() }
10.2 删除某个 key
kotlin
context.dataStore.edit { prefs ->
prefs.remove(PreferenceKeys.MUSIC_ID)
}
11. 与 SharedPreferences 的对比
| 对比项 | SharedPreferences | DataStore |
|---|---|---|
| 线程安全 | ❌ | ✅ |
| 写入方式 | 同步 / apply | 协程 |
| 原子性 | ❌ | ✅ |
| 数据监听 | ❌ | Flow |
| 官方推荐 | ❌ | ✅ |
12. 常见错误(必须注意)
❌ 1. 把 DataStore 当数据库用
- 不适合大量数据
- 不适合高频写入
❌ 2. 每次都新建 DataStore
kotlin
preferencesDataStore(...) // ❌ 多次调用
👉 必须是单例
❌ 3. 在主线程调用 .first()
kotlin
dataStore.data.first() // ❌ 可能阻塞
👉 应在 Dispatchers.IO 或协程中调用
❌ 4. 存复杂对象
Preferences DataStore 不支持对象
👉 复杂结构请使用 Proto DataStore
13. 什么时候不该用 DataStore?
❌ 大量数据
❌ 高频实时数据(如 1 秒一次进度)
❌ 复杂关系型数据
👉 这些场景请用:
- Room
- 文件
- 数据库
14. 最佳实践总结(工程级)
- 一个 DataStore 一个文件
- Key 集中管理
- edit 中一次写完
- Flow + ViewModel + Compose
- 高频数据做节流 / 阈值写
15. 一句话总结
DataStore Preferences = 线程安全 + 原子写入 + Flow 化的 SharedPreferences