Android Jetpack Room 新手使用指南

Room 是 Android Jetpack 中的 SQLite 对象映射库,用于简化本地数据库操作,提供编译时 SQL 校验、LiveData/Flow 集成、RxJava 支持等功能。本文将从以下其核心概念、使用示例、适用场景、注意事项及版本兼容性等方面进行讲解。

一、核心组件

1. Entity(实体类)

  • 定义数据库表结构,通过注解配置主键、列名、索引等。

2. DAO(Data Access Object)

  • 接口或抽象类,定义数据库操作方法(增删改查)。

3. Database(数据库类)

  • 继承 RoomDatabase 的抽象类,管理数据库连接和 DAO 实例。

二、使用示例

1. 基础配置

添加依赖

gradle 复制代码
// build.gradle (app)
dependencies {
    implementation "androidx.room:room-runtime:2.6.1"
    kapt "androidx.room:room-compiler:2.6.1"
    implementation "androidx.room:room-ktx:2.6.1" // Kotlin扩展
    // 可选:RxJava或Paging集成
    implementation "androidx.room:room-rxjava3:2.6.1"
    implementation "androidx.room:room-paging:2.6.1"
}

2. 定义 Entity

kotlin 复制代码
@Entity(tableName = "users", indices = [Index(value = ["name"], unique = true)])
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "name")
    val userName: String,
    val age: Int,
    @ColumnInfo(defaultValue = "false")
    val isAdmin: Boolean
)

3. 定义 DAO

kotlin 复制代码
@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(user: User)

    @Update
    suspend fun update(user: User)

    @Delete
    suspend fun delete(user: User)

    @Query("SELECT * FROM users WHERE id = :userId")
    fun getUserById(userId: Int): Flow<User?>

    @Query("SELECT * FROM users WHERE isAdmin = 1")
    fun getAdmins(): PagingSource<Int, User> // 与Paging集成
}

4. 定义 Database

kotlin 复制代码
@Database(
    entities = [User::class],
    version = 1,
    exportSchema = true
)
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) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(
                context.applicationContext,
                AppDatabase::class.java,
                "app_database"
            ).addCallback(object : RoomDatabase.Callback() {
                override fun onCreate(db: SupportSQLiteDatabase) {
                    super.onCreate(db)
                    // 数据库首次创建时初始化数据
                }
            }).build()
        }
    }
}

5. 在 ViewModel 中操作数据

kotlin 复制代码
class UserViewModel(private val userDao: UserDao) : ViewModel() {
    val admins: Flow<List<User>> = userDao.getAdmins().flowOn(Dispatchers.IO)

    fun addUser(name: String, age: Int) {
        viewModelScope.launch {
            userDao.insert(User(userName = name, age = age))
        }
    }
}

6. 数据库迁移(版本升级)

kotlin 复制代码
// 版本1 → 版本2:新增字段 email
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE users ADD COLUMN email TEXT DEFAULT ''")
    }
}

// 更新Database配置
Room.databaseBuilder(...)
    .addMigrations(MIGRATION_1_2)
    .build()

三、适用场景

1. 本地数据持久化

  • 用户信息、应用配置、缓存数据等需持久化存储的场景。

2. 复杂查询需求

  • 多表关联查询、聚合函数(SUM/COUNT)等。

3. 离线优先架构

  • 结合 RemoteMediator 实现先加载本地数据,再同步远程数据。

4. 响应式 UI

  • 通过 FlowLiveData 监听数据变化,实时更新界面。

四、注意事项

1. 主线程限制

  • 默认禁止在主线程执行数据库操作,需使用协程、RxJava 或异步任务。

  • 调试时可临时启用 allowMainThreadQueries(),但生产环境禁用。

    kotlin 复制代码
    Room.databaseBuilder(...)
        .allowMainThreadQueries() // 仅用于测试
        .build()

2. 索引优化

  • 对高频查询字段(如 name)添加索引,但避免过度索引导致写入性能下降。

    kotlin 复制代码
    @Entity(indices = [Index(value = ["name"], orders = [Order.ASC])])

3. 数据库升级风险

  • 修改表结构时需谨慎处理迁移逻辑,建议使用 MigrationTestHelper 进行单元测试。

    kotlin 复制代码
    @Test
    fun testMigration1To2() {
        val helper = MigrationTestHelper(...)
        val db = helper.runMigrationsAndValidate("app_database", 2, true, MIGRATION_1_2)
        // 验证字段是否存在
    }

4. 类型转换

  • 复杂类型(如 Date)需通过 TypeConverter 序列化:

    kotlin 复制代码
    class Converters {
        @TypeConverter
        fun fromTimestamp(value: Long?) = value?.let { Date(it) }
    
        @TypeConverter
        fun dateToTimestamp(date: Date?) = date?.time
    }

    @Database 注解中添加:

    kotlin 复制代码
    @TypeConverters(Converters::class)

五、版本兼容性

Room 版本 最低 Android API 主要特性
2.2.x API 16 (Android 4.1) 支持 Kotlin 协程、预编译数据库。
2.4.x API 16 增强 Flow 支持、改进 Paging 3 集成。
2.5.x API 16 支持 Upsert 注解、自动迁移(AutoMigration)。
2.6.x API 16 提升性能、支持 @Fts4 全文搜索注解。
  • AutoMigration(自动迁移)

    从 Room 2.4.0 开始,若表结构变更仅涉及新增/删除列,可自动生成迁移逻辑:

    kotlin 复制代码
    @Database(
        version = 2,
        autoMigrations = [
            AutoMigration(from = 1, to = 2)
        ]
    )

六、与 Hilt 集成(依赖注入)

一文带你了解 Android 中 Dagger/Hilt 的原理和简单使用

kotlin 复制代码
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
    @Provides
    @Singleton
    fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
        return AppDatabase.getInstance(context)
    }

    @Provides
    fun provideUserDao(database: AppDatabase): UserDao {
        return database.userDao()
    }
}

// 在 ViewModel 中注入
@HiltViewModel
class UserViewModel @Inject constructor(
    private val userDao: UserDao
) : ViewModel() { ... }

七、总结

  • 优势:编译时 SQL 校验、与 Jetpack 组件深度集成、简化数据库操作。

  • 最佳实践

    • 使用 FlowLiveData 实现响应式 UI。
    • 通过 TypeConverter 处理复杂数据类型。
    • 利用 AutoMigration 简化数据库升级。
    • 使用 @Transaction 确保多步骤操作的原子性。
    kotlin 复制代码
    @Dao
    interface UserDao {
        @Transaction
        suspend fun updateUserName(oldName: String, newName: String) {
            // 多个操作在一个事务中执行
        }
    }

通过合理使用 Room,开发者可以高效管理本地数据,提升应用的稳定性和可维护性。

更多分享

  1. 一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)
  2. 一文带你吃透Kotlin协程的launch()和async()的区别
  3. Kotlin 作用域函数(let、run、with、apply、also)的使用指南
  4. Android 详解:高频使用的 8 种设计模式的核心思想和代码实现
  5. 一文带你吃透Kotlin中 lateinit 和 by lazy 的区别和用法
  6. Android ContentProvider 详解及结合 Jetpack Startup 的优化实践
相关推荐
彼方卷不动了6 小时前
【技术学习】在 Android 上用 Kotlin 实现支持多图层的 OpenGL 渲染管线
android·kotlin·opengl
ljt27249606619 小时前
Compose笔记(十三)--事件总线
笔记·android jetpack
行墨10 小时前
Kotlin高阶函数初探
kotlin
wangz7611 小时前
kotlin,jetpack compose 最简导航(navigation)案例学习
kotlin·navigation·jetpack compose
casual_clover12 小时前
Android 中隐藏标题栏和状态栏的方法
android·kotlin
我命由我1234514 小时前
Android Gradle 插件问题:The option ‘android.useDeprecatedNdk‘ is deprecated.
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
QING61816 小时前
Kotlin digitToChar用法及代码示例
android·kotlin·源码阅读
QING61816 小时前
Kotlin all用法及代码示例
android·kotlin·源码阅读
QING61816 小时前
Kotlin ifBlank用法及代码示例
android·kotlin·源码阅读
QING61816 小时前
Kotlin dropWhile用法及代码示例
android·kotlin·源码阅读