06.1
持久化全景
按数据量、结构复杂度与安全性选型:偏好用 DataStore,结构化关系用 Room,大文件用文件系统,密钥用加密存储。
SharedPreferences 已过时
新项目用 DataStore(基于协程/Flow、类型安全、无主线程 ANR)替代老式 SharedPreferences。
06.2
DataStore
Preferences DataStore 存简单键值,暴露 Flow;读异步、不阻塞主线程。
val Context.dataStore by preferencesDataStore("settings")
suspend fun saveDark(v: Boolean) {
dataStore.edit { it[booleanPreferencesKey("dark")] = v }
}
val darkFlow: Flow<Boolean> = dataStore.data.map { it[booleanPreferencesKey("dark")] ?: false }06.3
Room
Room 是 SQLite 的编译期封装:Entity + DAO + Database,SQL 在编译期校验,直接返回 Kotlin 数据类与 Flow。
@Entity data class User(@PrimaryKey val id: Long, val name: String)
@Dao interface UserDao {
@Query("SELECT * FROM User WHERE id = :id")
fun observe(id: Long): Flow<User>
@Insert suspend fun insert(u: User)
}
@Database(entities = [User::class], version = 1)
abstract class AppDb : RoomDatabase() { abstract fun userDao(): UserDao }06.4
SQLite 直连
极简或高度定制场景可用 SQLiteOpenHelper 手写 SQL,但需自行管理游标与线程。
优先 Room
直连易出错、无编译期校验。除非特殊需求,一律用 Room。
06.5
文件与媒体
内部存储 filesDir 私有无备份;外部/媒体用 MediaStore 或 Scoped Storage;缓存用 cacheDir。
val file = File(context.filesDir, "profile.json")
file.writeText(json) // 内部存储,私有06.6
安全存储
令牌、密钥用 EncryptedSharedPreferences 或 Android Keystore,明文绝不放普通文件。
val master = MasterKey.Builder(ctx).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
val enc = EncryptedSharedPreferences.create(ctx, "secret", master,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM)
enc.edit().putString("token", t).apply()06.7
选型对照
| 方案 | 适合 |
|---|---|
| DataStore | 偏好/小键值(异步、类型安全) |
| Room | 结构化关系数据 |
| 文件 | 文档/媒体/缓存 |
| 加密存储 | 密钥、令牌 |
06.8
常见陷阱
默认禁止主线程访问数据库。用 suspend/Flow/RxJava 变体在后台执行,或允许主线程(不推荐)。
用 Migration 定义版本间 SQL,或用 fallbackToDestructiveMigration(会清数据,仅开发用)。提供迁移否则用户升级崩溃。
06.9