一、Jetpack Room 概述
Jetpack Room 是 Android 官方推出的持久性库,属于 Android Jetpack 组件的一部分。它简化了 SQLite 数据库的操作,通过注解和编译时检查提供类型安全的数据库访问。Room 包含三个核心组件:
-
@Entity:定义数据库表结构。 -
@Dao(Data Access Object):包含访问数据库的方法。 -
@Database:定义数据库配置的抽象类。
二、基本用法
1.添加依赖
在build.gradle(app)文件中添加:
dependencies {
// Room 核心库
implementation "androidx.room:room-runtime:2.5.2"
// 注解处理器(编译时生成代码)
kapt "androidx.room:room-compiler:2.5.2"
// Kotlin 扩展(支持协程、Flow 等)
implementation "androidx.room:room-ktx:2.5.2"
// 协程(Room 异步操作依赖)
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
}
同步项目后,Room 会在编译时生成必要的代码(如 DAO 实现类)
2.创建实体类(Entiy)
用 @Entity 注解标记数据表
// 表名默认是类名,可通过 tableName 自定义
@Entity(tableName = "users")
data class User(
// 主键(autoGenerate = true 表示自增)
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
// 普通字段(默认允许为 null,添加 non-null 修饰符则不允许)
val name: String,
// 可通过 @ColumnInfo 自定义列名
@ColumnInfo(name = "user_age")
val age: Int,
// 添加唯一约束(避免重复值)
@ColumnInfo(unique = true)
val email: String
)
在这个示例中,@Entiy注解指定了表名,@PrimaryKey 注解指定了主键,autoGenerate = true 表示主键自动生成,用 @Ignore 标记不需要存入数据库的字段
3.创建DAO接口(数据访问接口)
DAO是一个接口,用于定义数据库操作的方法,使用@Dao注解标记,通过注解声明数据库操作(无需实现类,Room自动生成)
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
// 插入数据(onConflict 处理冲突策略:REPLACE 表示覆盖)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
// 插入多条数据(参数为可变参数)
@Insert
suspend fun insertUsers(vararg users: User)
// 更新数据
@Update
suspend fun updateUser(user: User)
// 删除数据
@Delete
suspend fun deleteUser(user: User)
// 查询所有用户(返回 Flow,数据变化时自动通知观察者)
@Query("SELECT * FROM users ORDER BY name ASC")
fun getAllUsers(): Flow<List<User>>
// 按条件查询(:age 引用函数参数,编译时检查参数名)
@Query("SELECT * FROM users WHERE user_age > :minAge")
suspend fun getUsersOlderThan(minAge: Int): List<User>
// 按 ID 查询单条数据(返回 nullable,无数据时为 null)
@Query("SELECT * FROM users WHERE id = :userId LIMIT 1")
suspend fun getUserById(userId: Int): User?
// 删除所有数据
@Query("DELETE FROM users")
suspend fun deleteAllUsers()
}
DAO 关键注解:
-
@Insert/@Update/@Delete:简化增删改操作(自动生成 SQL); -
@Query:执行自定义 SQL(支持SELECT/DELETE/UPDATE,必须指定 SQL 语句); -
支持返回类型:
List<T>(单次查询)、Flow<List<T>>(观察数据变化)、T?(单条数据)等; -
异步操作:用
suspend修饰函数(配合协程),避免阻塞主线程
4.创建数据库类(Database)
数据库类继承自 RoomDatabase,使用 @Database 注解标记。
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
// 关联的表(entities 数组)、版本号(version)
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
// 提供 DAO 实例(Room 自动实现)
abstract fun userDao(): UserDao
// 单例模式(避免创建多个数据库实例)
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
// 双重校验锁确保单例
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext, // 用 ApplicationContext 避免内存泄漏
AppDatabase::class.java,
"my_database" // 数据库文件名(存储路径:/data/data/包名/databases/)
).build()
INSTANCE = instance
instance
}
}
}
}
-
@Database注解指定了数据库包含的实体类和数据库版本,abstract fun userDao()方法用于获取UserDao实例 -
exportSchema = false关闭 schema 导出(开发阶段可关闭,生产环境建议开启用于迁移)。
5.使用Room操作数据库
在 Activity/Fragment 中通过协程调用 DAO 方法,实现数据读写
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.collect
class MainActivity : AppCompatActivity() {
private lateinit var userDao: UserDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 获取 DAO 实例
val db = AppDatabase.getInstance(applicationContext)
userDao = db.userDao()
// 1. 插入数据(在协程中执行异步操作)
lifecycleScope.launch {
val user1 = User(name = "张三", age = 25, email = "zhangsan@example.com")
val user2 = User(name = "李四", age = 30, email = "lisi@example.com")
userDao.insertUsers(user1, user2)
}
// 2. 观察数据变化(Flow 会自动在主线程回调)
lifecycleScope.launch {
userDao.getAllUsers().collect { users ->
Log.d("RoomDemo", "当前用户列表:$users")
// 更新 UI(如刷新 RecyclerView)
}
}
// 3. 按条件查询
lifecycleScope.launch {
val adults = userDao.getUsersOlderThan(18)
Log.d("RoomDemo", "成年用户:$adults")
}
// 4. 更新数据
lifecycleScope.launch {
val user = userDao.getUserById(1)?.copy(age = 26) // 修改年龄
if (user != null) {
userDao.updateUser(user)
}
}
}
}
三、数据库版本升级
当表结构变更(如新增列、修改字段)时,需通过 Migration 处理升级,避免数据丢失:
步骤1.创建Migration 类:
定义从旧版本到新版本的升级逻辑:
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
// 从版本 1 升级到版本 2(新增 "address" 列)
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
// 执行 ALTER TABLE 语句添加列
database.execSQL("ALTER TABLE users ADD COLUMN address TEXT")
}
}
// 从版本 2 升级到版本 3(新增 "phone" 列)
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT")
}
}
步骤2:在 Database 中添加 Migration
@Database(entities = [User::class], version = 3, exportSchema = false) // 版本号从 1 → 3
abstract class AppDatabase : RoomDatabase() {
// ... 省略其他代码
companion object {
fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"my_database"
)
// 添加所有升级规则(从 1→2,2→3)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
INSTANCE = instance
instance
}
}
}
}
注意:
-
版本号必须递增(如 1→2→3,不能跳跃);
-
若未添加对应的 Migration,Room 会默认删除旧数据库并重建(导致数据丢失);
-
复杂升级(如新增表、修改主键)需编写对应的 SQL 语句。

1295

被折叠的 条评论
为什么被折叠?



