Android Jetpack ROOM 数据库框架使用
前言
- 谷歌推出
Jetpack
已经好久了,之前一直断断续续的使用过一些,但是都没有整理过.学习就要记笔记或者在项目中实践,不然很容易时间长的话忘记 - 谷歌文档地址
- 版本说明 大家最好使用稳定版本,之前
AndroidX
升级新版本遇到的5.1
和5.0
的系统WebView必崩的问题,我建议使用exclude
同意一下AdnroidX
的版本
配置dependencies
- 使用Kotlin记得相关Module使用apt
apply plugin: 'kotlin-kapt'
dependencies {
def room_version = "2.2.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}
- ROOM架构图(摘自谷歌官方文档)
配置实体类
@PrimaryKey
表示主键,autoGenerate
属性表示是否自增@ColumnInfo
表示指定列名@Ignore
表示忽略此字段,表中就没有此字段
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long,
@ColumnInfo(name = "name")
var name: String?,
@ColumnInfo(name = "address")
var address: String?,
@Ignore
var birthday: String?
)
配置DAO
@Dao
interface UserDao {
/**
* 查询所有用户
*/
@Query("SELECT * FROM user")
fun getAll(): List<User>
/**
* 根据id查询到某一个用户
*/
@Query("SELECT * FROM user WHERE id=(:uid) ")
fun loadAllById(uid: Int): User
/**
* 根据用户id数组查询到一批用户
*/
@Query("select * from user where id in (:ids)")
fun loadAllByIds(ids: IntArray): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUser(user: User?)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUser(users: List<User>)
@Insert
fun deleteUser(user: User?)
//只返回name的子集
@Query("SELECT name From user")
fun loadFullName(): List<NameTuple>
}
data class NameTuple(
@ColumnInfo(name = "name") var name: String?
)
配置DataBase单例类
-
操作数据库请在子线程操作,UI线程刷新,
-
当然Room也支持在主线程操作,不过不建议,如果需要声明在主线程操作,记得声明
fallbackToDestructiveMigration()
属性
@Database(entities = [User::class], version = 1)
abstract class UserDataBase : RoomDatabase() {
companion object {
@Volatile
private var INSTANCE: UserDataBase? = null
fun getInstance(context: Context): UserDataBase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: (
Room.databaseBuilder(
context.applicationContext,
UserDataBase::class.java,
"user_database.db"
).allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build()
).also {
INSTANCE = it
}
}
}
abstract fun userDao(): UserDao
}
操作数据库
插入数据
-
插入一条数据
-
OnConflictStrategy.REPLACE
表示插入的时候有该数据的情况下会直接替换
interface UserDao{
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUser(user: User?)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUser(users: List<User>)
}
UserDataBase.getInstance(this).userDao().insertUser(User(1, "小明", "北京朝阳区"))
UserDataBase.getInstance(this).userDao().insertUser(User(2, "小红", "北京通州区"))
id | name | address |
---|---|---|
1 | 小明 | 北京朝阳区 |
2 | 小红 | 北京通州区 |
- 插入一批数据
val userList = arrayListOf<User>(User(3, "小张", "北京丰台区"),User(4, "小王", "北京海淀区"))
UserDataBase.getInstance(this).userDao().insertUser(userList)
id | name | address |
---|---|---|
1 | 小明 | 北京朝阳区 |
2 | 小红 | 北京通州区 |
3 | 小张 | 北京丰台区 |
4 | 小王 | 北京海淀区 |
查询数据
- 可以参照
sql
语句做一些条件查询,下面是一些基本的简单查找
interface UserDao{
@Query("SELECT * FROM user")
fun getAll(): List<User>
/**
* 根据id查询到某一个用户
*/
@Query("SELECT * FROM user WHERE id = (:uid) ")
fun loadAllById(uid: Int): User
/**
* 根据用户id数组查询到一批用户
*/
@Query("select * from user where id in (:ids)")
fun loadAllByIds(ids: IntArray): List<User>
/**
* 查询到的用户只返回user表中的name列信息
*/
@Query("SELECT name From user")
fun loadFullName(): List<NameTuple>
}
UserDataBase.getInstance(this).userDao().getAll()
UserDataBase.getInstance(this).userDao().loadAllById(1)
UserDataBase.getInstance(this).userDao().loadAllByIds(intArrayOf(1,2))
删除数据
UserDataBase.getInstance(this).userDao().deleteUser(User(1, "小明", "北京朝阳区"))
//同样也可以传入list批量删除
更新数据
UserDataBase.getInstance(this).userDao().updateUser(User(2, "小小红", "上海"))
升级数据库
- 需要在
Database
中version+1
@Database(entities = [User::class], version = 2)
abstract class UserDataBase : RoomDatabase() {}
-
也可以直接在构建
DataBase
类的时候声明fallbackToDestructiveMigration()
属性,不过这样升级会导致之前的数据情况 -
version增加的同事,提供Migration,这样会保证数据的正常,记得在对应
Entity
也增加对应的属性 -
Migration也支持直接从version1->version4,不过我感觉还是一步一步升级比较符合,避免未知错误
fun getInstance(context: Context): UserDataBase = INSTANCE ?: synchronized(this) { INSTANCE ?: ( Room.databaseBuilder( context.applicationContext, UserDataBase::class.java, "user_database.db" ).allowMainThreadQueries() .addMigrations(migration) .build() ).also { INSTANCE = it } } private val migration = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL( "ALTER TABLE user " + " ADD COLUMN age INTEGER" ) } }