数据持久化:Room数据库集成、DataStore替代SharedPreferences、文件存储、序列化与反序列化

数据持久化,说白了就是让App的数据活得更久。App一关,数据就丢?那用户肯定不干。今天我们来聊聊Android里那几套持久化方案,我会结合自己的踩坑经历,帮你理清思路。

一、Room数据库集成

Room是Google官方推荐的ORM框架,底层封装了SQLite。我个人习惯用Room,因为它编译期会检查SQL语法,少了很多运行时崩溃。

1. 添加依赖

// build.gradle.kts (Module)
plugins {
    id("kotlin-kapt")
}

dependencies {
    val roomVersion = "2.6.1"
    implementation("androidx.room:room-runtime:$roomVersion")
    implementation("androidx.room:room-ktx:$roomVersion")
    kapt("androidx.room:room-compiler:$roomVersion")
}

2. 定义实体与DAO

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    val name: String,
    val age: Int
)

@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    suspend fun getAll(): List<User>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(user: User)

    @Delete
    suspend fun delete(user: User)
}

3. 创建数据库

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "my_database"
                ).build().also { INSTANCE = it }
            }
        }
    }
}
⚠️ 注意: 数据库版本升级时,记得写Migration,否则会丢数据。我曾经在线上版本直接fallbackToDestructiveMigration(),结果用户数据全没了……从那以后我再也不敢偷懒了。

二、DataStore替代SharedPreferences

SharedPreferences有个老毛病——同步读写容易卡UI线程,而且不支持类型安全。DataStore就是来替代它的。

1. Preferences DataStore

val Context.dataStore by preferencesDataStore(name = "settings")

val THEME_KEY = booleanPreferencesKey("dark_mode")

suspend fun saveTheme(context: Context, isDark: Boolean) {
    context.dataStore.edit { preferences ->
        preferences[THEME_KEY] = isDark
    }
}

val themeFlow: Flow<Boolean> = context.dataStore.data.map { preferences ->
    preferences[THEME_KEY] ?: false
}

2. Proto DataStore(类型安全)

如果你需要强类型的数据结构,用Proto DataStore更合适。它基于Protocol Buffers,定义一次schema,到处使用。

// 定义 proto 文件
syntax = "proto3";
option java_package = "com.example.datastore";
option java_multiple_files = true;

message UserPreferences {
    bool dark_mode = 1;
    int32 font_size = 2;
}

// 使用
val Context.userPreferencesStore by protoDataStore<UserPreferences>(
    fileName = "user_prefs.pb",
    serializer = UserPreferencesSerializer
)
💡 我的建议: 简单键值对用Preferences DataStore,复杂配置用Proto DataStore。别一上来就用Proto,过度设计也是坑。

三、文件存储

有些场景不适合数据库,比如存图片、日志、缓存文件。这时候就得用文件存储。

1. 内部存储 vs 外部存储

存储类型 路径 特点
内部存储 context.filesDir 私有,其他App无法访问,卸载即删除
外部存储 Environment.getExternalStorageDirectory() 可被用户和其他App访问,需要权限

2. 写入与读取示例

// 写入内部存储
fun writeToFile(context: Context, fileName: String, content: String) {
    context.openFileOutput(fileName, Context.MODE_PRIVATE).use {
        it.write(content.toByteArray())
    }
}

// 读取内部存储
fun readFromFile(context: Context, fileName: String): String {
    return context.openFileInput(fileName).bufferedReader().readText()
}
⚠️ 注意: Android 10以后,外部存储的访问方式变了。别再直接用Environment.getExternalStorageDirectory(),改用MediaStore或SAF(Storage Access Framework)。我有个项目就因为没适配,在Android 11上直接崩溃。

四、序列化与反序列化

数据要持久化,就得先变成字节流。这个过程就是序列化。反过来叫反序列化。

1. Serializable vs Parcelable

方案 优点 缺点
Serializable Java原生,使用简单 反射机制,性能差,容易产生大量临时对象
Parcelable Android专用,性能好 需要手写模板代码(可用插件生成)

2. Kotlin序列化(kotlinx.serialization)

我个人更推荐用kotlinx.serialization,它编译期生成代码,性能接近手写,而且支持JSON、ProtoBuf等多种格式。

// 添加依赖
plugins {
    kotlin("plugin.serialization") version "1.9.0"
}
dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}

// 定义可序列化类
@Serializable
data class Person(val name: String, val age: Int)

// 序列化
val json = Json.encodeToString(person)

// 反序列化
val obj = Json.decodeFromString<Person>(json)
💡 避坑指南: 我曾经用Serializable存一个复杂的对象图,结果序列化后文件巨大,反序列化还经常OOM。后来换成kotlinx.serialization,问题全解决了。记住:序列化不是越简单越好,要看场景。

五、知识体系总览

下面这张图,是我自己总结的数据持久化选型思路。你想想看,是不是这个理?

Android 数据持久化选型指南 数据持久化 Room 数据库 DataStore 文件存储 结构化数据 / 复杂查询 键值对 / 类型安全 大文件 / 二进制数据 序列化(kotlinx.serialization / Parcelable) 贯穿所有持久化方案

嗯,到这里数据持久化的核心内容就讲完了。记住一句话:没有银弹。Room适合结构化数据,DataStore适合配置项,文件存储适合大块数据。选型时多想想你的业务场景,别盲目跟风。

公众号:蓝海资料掘金营,微信 deep3321