JetPack Room教程

一、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 语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值