处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的使用场景是缓存相关的数据,这样一来,当设备无法访问网络时,用户仍然可以在离线状态下浏览该内容。
Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。具体来说,Room 具有以下优势:
- 提供针对 SQL 查询的编译时验证。
- 提供方便注解,可最大限度减少重复和容易出错的样板代码。
- 简化了数据库迁移路径。
Room 包含三个主要组件:
数据库类为应用提供与该数据库关联的 DAO 的实例。反过来,应用可以使用 DAO 从数据库中检索数据,作为关联的数据实体对象的实例。此外,应用还可以使用定义的数据实体更新相应表中的行,或者创建新行供插入。图 1 说明了 Room 的不同组件之间的关系。

需要先在build.gradle.kts中添加kapt插件
alias(libs.plugins.jetbrainsKotlinKapt)
plugins {
alias(libs.plugins.jetbrainsKotlinKapt) apply false
}
然后再app的gradle中添加如下依赖
//room依赖
val room_version = "2.6.1"
implementation("androidx.room:room-runtime:$room_version")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$room_version")
添加插件:
plugins {
id 'org.jetbrains.kotlin.kapt'
}
添加依赖:
def room_version = "2.6.1"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// To use Kotlin annotation processing tool (kapt)
kapt "androidx.room:room-compiler:$room_version"
1.创建User实体类
@Entity(tableName = "user2")
data class User(
@ColumnInfo(name = "username")
var userName: String? = null,
@ColumnInfo(name = "password")
var userPassword: String? = null
) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0
}
2.添加注解:
- 默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。
- Room 默认使用字段名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 @ColumnInfo 注解添加到该字段并设置 name
属性。- 每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行。执行此操作的最直接方式是使用 @PrimaryKey
为单个列添加注解(注意:如果您需要 Room 为实体实例分配自动 ID,请将 @PrimaryKey 的 autoGenerate
属性设为 true。)- 默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果某个实体中有您不想保留的字段,则可以使用 @Ignore
为这些字段添加注解
interface UserDao {
@Query("SELECT * FROM user2")
fun getAll(): List<User>
@Delete
fun delete(user: User)
@Update
fun updateUsers(vararg users: User)
//这个注解表示如果数据已在数据库中存在增进行替换
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(users: List<User>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(user: User)
//返回User的id值,判断是否添加成功
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertReturnId(user: User) : Long
@Query("SELECT * FROM user2 WHERE username = :userName AND password = :userPassword")
fun queryUser(userName: String, userPassword: String): User?
}
这里通过单例双重验证进行创建
//这里exportSchema
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserDataBase : RoomDatabase() {
companion object {
private var instance: UserDataBase? = null
fun getInstance(context: Context): UserDataBase? {
if (instance == null) {
synchronized(Companion::class.java) {
if(null == instance) {
instance = Room.databaseBuilder(context, UserDataBase::class.java, "user.db")
.addMigrations()
.allowMainThreadQueries()//表示允许在主线程中进行数据库的操作
.build()
}
}
}
return instance
}
}
abstract fun getUserDao(): UserDao
}
注:可能会报 Schema export directory is not provided to the annotation processor异常
有两种方式解决:
1.在Database注解中添加 exportSchema = false
2.在app的build.gradle中的defaultConfig下添加以下配置
javaCompileOptions {
annotationProcessorOptions {
arrayOf("room.schemaLocation" to "$projectDir/schemas")
}
}
- 该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
- 该类必须是一个抽象类,用于扩展 RoomDatabase。
- 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
val userDataBase = UserDataBase.getInstance(this)
//在子线程中去运行
userDataBase?.runInTransaction {
val userDao: UserDao = db.userDao()
val users = userDao.getAll()
}
通过Android Studio自带的工具就能够查看

或者在Device Explorer中的data/data/包名下的databases目录中,将db文件拉出来用其他数据库工具查看

Room基本用法已经讲完了,更多详细内容请看 官方文档:https://developer.android.google.cn/training/data-storage/room?hl=zh-cn#groovy
像数据库持久化的其他开源框架还有LitPal等
LitePal介绍
参考文章:
Android-第十三节04Room框架详解