Room
- SQL基础上的一个抽象层
使用
- 引入依赖
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation("androidx.room:room-ktx:$room_version")
- 定义数据库表
使用@Entity注解
@Entity(tableName = "User")
class User {
@PrimaryKey
var id: Int = 0
@ColumnInfo(name = "name")
var name: String = ""
@ColumnInfo(name = "address", defaultValue = "")
var address: String = ""
}
- 定义数据表操作接口
使用@Dao注解
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
@Query("select * from user")
fun getAll() : Flow<List<User>>
}
- 定义数据库接口
使用&#64;Database注解
&#64;Database(
entities &#61; [User::class],
version &#61; 1,
)
abstract class UserDataBase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var userDataBase: UserDataBase? &#61; null
fun get(context: Context): UserDataBase {
return userDataBase ?: synchronized(this) {
Room.databaseBuilder(context, UserDataBase::class.java, "lcj")
.build()
.also {
userDataBase &#61; it
}
}
}
}
}
- 使用
class UserViewModel(app:Application) : AndroidViewModel(app) {
suspend fun insert(id: Int, name: String, address: String) {
val user &#61; User()
user.id &#61; id
user.name &#61; name
user.address &#61; address
UserDataBase.get(getApplication()).userDao().insert(user)
}
fun getAll(): Flow<List<User>> {
return UserDataBase.get(getApplication()).userDao().getAll().catch {
}.flowOn(Dispatchers.IO)
}
}
迁移
自动迁移
使用自动迁移&#xff0c;需要提供schema.location配置且&#64;DataBase中的exportSchema必须设置为TRUE&#xff08;默认为TRUE&#xff09;
- build.gradle中进行如下配置&#xff0c;用于生成每个版本的数据库记录&#xff0c;Room用来跟踪数据库的变更
defaultConfig {
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
}
- 新增列address
&#64;Entity(tableName &#61; "User")
class User {
&#64;PrimaryKey
var id: Int &#61; 0
&#64;ColumnInfo(name &#61; "name")
var name: String &#61; ""
&#64;ColumnInfo(name &#61; "address", defaultValue &#61; "")
var address: String &#61; ""
}
- 在Database注解中version升级到对应版本&#xff0c;且autoMigrations添加from to
&#64;Database(
entities &#61; [User::class],
version &#61; 2,
autoMigrations &#61; [
AutoMigration(from &#61; 1, to &#61; 2)
]
)
abstract class UserDataBase : RoomDatabase() {
- 生成的跟踪文件如下
注意&#xff1a;上面步骤&#xff0c;完成数据库中添加一列的升级。每当数据库版本再次改变时&#xff0c;您只需更新 autoMigrations 列表&#xff0c;添加一个新的AutoMigration即可。上述数据库表中新增了address列&#xff0c;对于自动迁移&#xff0c;Room自动会检测中这种变更&#xff0c;不需要开发者做其他操作。
但是&#xff0c;有些自动迁移操作&#xff0c;Room无法检测出变化&#xff0c;需要开发者添加额外的spec,如&#xff0c;修改表名、列名、删除表、删除列&#xff0c;需要添加如下代码
&#64;DeleteTable(tableName)
&#64;RenameTable(fromTableName, toTableName)
&#64;DeleteColumn(tableName, columnName)
&#64;RenameColumn(tableName, fromColumnName, toColumnName)
下面代码是从版本2升级到版本3&#xff0c;用于修改列名&#xff0c;此处在AutoMigration中添加了spec
&#64;Database(
entities &#61; [User::class],
version &#61; 3,
autoMigrations &#61; [
AutoMigration(from &#61; 1, to &#61; 2),
AutoMigration(from &#61; 2, to &#61; 3, spec &#61; UserDataBase.Migration2to3::class)
]
)
abstract class UserDataBase : RoomDatabase() {
abstract fun userDao(): UserDao
&#64;RenameColumn(tableName &#61; "User", fromColumnName &#61; "address", toColumnName &#61; "addressAt")
class Migration2to3 : AutoMigrationSpec
手动迁移
针对手动&#xff0c;Room 提供了 Migration 类。每当您要更改复杂的数据库时&#xff0c;您就得使用这个类。如&#xff1a;将数据库中的一个表拆分成两个不同的表&#xff0c;Room 无法检测到拆分的执行过程&#xff0c;也不能自动检测到需要移动的数据。因此这个时候&#xff0c;您需要实现一个 Migration 类&#xff0c;并通过 addMigrations() 的方法将其添加至 databaseBuilder() 中。
companion object {
private var userDataBase: UserDataBase? &#61; null
private val migration &#61; object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
}
}
fun get(context: Context): UserDataBase {
return userDataBase ?: synchronized(this) {
Room.databaseBuilder(context, UserDataBase::class.java, "lcj")
.addMigrations(migration).build()
.also {
userDataBase &#61; it
}
}
}
}