3. Preferences DataStore 基础配置:Kotlin 序列化依赖与 SharedPreferences 迁移辅助类
3.1 原理概述
Preferences DataStore 是 Jetpack DataStore 的键值对实现,以类型安全的 Preferences 对象存储数据。它使用 Kotlin 序列化(kotlinx-serialization)将 Set<String> 等复杂类型进行编码/解码,而基本类型(Int、Long、Float、Boolean、String)直接通过代理存取。
从 SharedPreferences 迁移时,DataStore 提供了 SharedPreferencesMigration 辅助类,自动读取旧文件并写入新 DataStore,避免数据丢失。迁移是无损的,且在首次读取 DataStore 时同步执行。
核心依赖项:
androidx.datastore:datastore-preferences– Preferences DataStore 核心库org.jetbrains.kotlinx:kotlinx-serialization-json– 用于序列化Set<String>等复杂类型
3.2 实现流程(Gradle 依赖配置)
- 添加 BOM(可选):确保 DataStore 版本与 Compose/Lifecycle 兼容。
- 添加 Preferences DataStore 依赖:在
app/build.gradle.kts中引入。 - 添加 Kotlin 序列化插件:在项目根
build.gradle.kts应用插件,并在模块中配置。
版本建议:DataStore 1.0.0 及以上版本均支持迁移。推荐使用 1.1.1 或最新稳定版。
3.3 关键代码与配置示例
模块级 build.gradle.kts
plugins {
id("com.android.application")
kotlin("android")
kotlin("plugin.serialization") // 必须应用
}
android {
// ... 其他配置
}
dependencies {
// Preferences DataStore
implementation("androidx.datastore:datastore-preferences:1.1.1")
// Kotlin 序列化 (用于 Set<String> 等)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}
项目级 build.gradle.kts(添加序列化插件 classpath)
plugins {
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.22" apply false
// 其他插件
}
3.4 创建 DataStore 实例并注册迁移
在 Application 或单例中创建 DataStore,并通过 SharedPreferencesMigration 迁移旧数据。
// 迁移辅助类:自动将 SharedPreferences 的键值对复制到 DataStore
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
name = "my_settings",
produceMigrations = { context ->
listOf(SharedPreferencesMigration(context, "old_shared_prefs_name"))
}
)
| 参数 | 类型 | 说明 |
|---|---|---|
name | String | DataStore 文件名(无需扩展名) |
produceMigrations | lambda | 返回 List<DataMigration<Preferences>>,包含 SharedPreferencesMigration |
SharedPreferencesMigration(context, sharedPreferencesName) | — | 第一个参数是 Context,第二个是旧的 SharedPreferences 文件名 |
3.5 调试与验证
- 首次启动 App 时,可通过
Logcat观察迁移日志:DataStore会输出Migrating from SharedPreferences...。 - 使用
Device File Explorer查看data/data/<package>/files/…/datastore/目录下是否生成新文件。 - 手动写入旧 SharedPreferences 数据,然后启动 App,检查 DataStore 能否正确读取。
常见错误:
- 未应用
kotlin.plugin.serialization导致Set<String>存储时抛出KotlinReflectionNotSupportedError。 - 迁移时指定的
sharedPreferencesName与实际文件名不匹配(不要带.xml后缀)。 - 多次调用
preferencesDataStore创建同一 Name 的实例可能引发IllegalStateException。
3.6 性能与稳定性优化
- 迁移过程在 IO 线程同步执行,应避免在主线程首次读取 DataStore(使用
first()或data()会触发挂起)。 - 如果旧 SharedPreferences 数据量极大(>100KB),建议在
produceMigrations中配置CustomMigration分批迁移,避免 ANR。 - 始终使用
catch处理 DataStore 的IOException,并在读取失败时提供默认值。
最佳实践:将 DataStore 实例声明为顶层委托或
Application 单例,确保全局唯一,并使用 kotlinx.coroutines.flow.Flow 进行响应式读取。
3.7 完整初始化模板(包含迁移与类型安全读取)
import android.content.Context
import android.content.SharedPreferences
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import androidx.datastore.preferences.core.stringPreferencesKey
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
name = "user_preferences",
produceMigrations = { context ->
listOf(SharedPreferencesMigration(context, "legacy_prefs"))
}
)
// 类型安全键:使用 stringPreferencesKey 而非编码枚举
val KEY_USER_NAME = stringPreferencesKey("user_name")
// 读取示例(在 ViewModel 中使用)
fun getUserName(context: Context): Flow<String?> {
return context.dataStore.data.map { preferences ->
preferences[KEY_USER_NAME]
}
}