用途:在 Android 与 KMP 上以协程响应式方式持久化键值偏好或小型类型化设置。同一 androidx.datastore:datastore-preferences-core 可运行于 Android、iOS、JVM,仅文件路径生成器因平台而异;Web 支持仅 1.3.0-alpha,且基于 sessionStorage/OPFS,非文件路径。
主要能力与选型:键值标志(主题、语言、引导完成)用 Preferences DataStore;单个类型化对象、多相关字段、需 schema 演进用 Typed DataStore + Serializer<T>;关系数据、索引、WHERE/JOIN、超过 100 条、分页用 Room;单次写入超过约 50KB 用 Room 或文件系统,因为 DataStore 每次编辑都会重写整个文件。经验法则:若 WHERE 子句有用,就用 Room。
两个陷阱:一是 .catch 必须精确匹配 IOException,不能用宽泛捕获,否则会吞掉 CancellationException 并隐藏序列化/损坏错误;示例:dataStore.data.catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e }.map { ... }。二是 Typed DataStore 的损坏恢复触发条件是 CorruptionException 而非 IOException,序列化器的 readFrom 需把解析失败包装为 CorruptionException,并配置 ReplaceFileCorruptionHandler,否则一个损坏文件会让所有读取永久失败。
KMP 工厂:commonMain 用 PreferenceDataStoreFactory.createWithPath(produceFile = { producePath().toPath() });Android 用 context.filesDir.resolve(PREFS_FILE).absolutePath;iOS 用 NSDocumentDirectory(经 NSFileManager);JVM 用 File(System.getProperty("user.home"), ".myapp"),不要用 java.io.tmpdir,系统可能在重启时清空。
限制:在 composable 中不要对 DataStore 使用 runBlocking,会阻塞主线程磁盘 I/O 并可能 ANR,且每次重组都会重跑;应暴露 StateFlow 并用 collectAsStateWithLifecycle 收集。本参考不覆盖 Preferences 键、edit { }、Serializer<T> 的基础用法。