引言
- 本文章旨在记录学习Android JetPack库下的Room数据库的使用,不作过于深入原理的讲解,如有问题和建议请留言讨论。
1、Room 库概念及架构示意图
概念
Google的介绍:
处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的使用场景是缓存相关的数据,这样一来,当设备无法访问网络时,用户仍然可以在离线状态下浏览该内容,
Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库
Room 库具有一下优势:
- 针对 SQL 查询的编译时验证
- 可最大限度减少重复和容易出错的样板代码的方便注解
- 简化了数据库迁移路径
架构示意图
主要组件
Room 包含三个主要组件
- 数据库类(Room Database),用于保存数据库并作为应用持久性数据底层连接的主要访问点
- 数据实体(Entities),用于表示应用的数据库中的表
- 数据访问对象 (Data Access Objects【Dao】),提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法
2、使用(Kotlin版【带注释】)
效果图展示
Android Room数据库操作
附上代码库地址:https://github/zqf-dev/ZRoomCode
依赖项添加
- 在build.gradle(Project)文件下添加版本
ext {
roomVersion = '2.4.2'
}
- 在build.gradle(app)文件下添加
plugins {
id 'com.android.application'
id 'kotlin-android'
// 添加kapt注解处理器
id 'kotlin-kapt'
}
android {
//排除原子函数模块并防止出现警告
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies{
//ktx
implementation 'androidx.core:core-ktx:1.7.0'
// room
implementation "androidx.room:room-ktx:$rootProject.roomVersion"
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
// 展示数据 adapter
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.7'
}
实体类(Entities)创建
数据库(Database)创建
*注:exportSchema:是否允许数据库架构将导出到给定的文件夹中【 默认true 】
/**
* Author: zqf
* Date: 2022/05/11
* 数据库创建
* entities: 实体类
* version: 数据库初始版本号
* exportSchema: 是否允许数据库架构将导出到给定的文件夹中【 默认true 】
*
*/
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class ZRoomDB : RoomDatabase() {
//创建userDao
abstract fun userDao(): UserDao
}
数据访问对象 (DAO)创建
/**
* Author: zqf
* Date: 2022/05/11
* 数据访问对象
*/
@Dao
interface UserDao {
// 查询
@Query("SELECT * FROM loginUser")
fun queryAllUser(): MutableList<User>
//根据姓名参数查询
@Query("SELECT * FROM loginUser WHERE name = :name")
fun queryFindUser(name: String): User?
// 添加单条数据
@Insert
fun addUser(vararg user: User)
// 添加批量数据
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun addBatchUser(list: MutableList<User>)
// 更新某一个数据
@Update
fun updateUser(vararg user: User)
//更新所有数据
@Query("UPDATE loginUser set age='50'")
fun updateAll()
//删除某一个数据
@Delete
fun deleteSingle(vararg user: User)
//删除表里所有数据
@Query("DELETE FROM loginUser")
fun deleteAllUser()
}
数据管理类封装
/**
* Author: zqf
* Date: 2022/05/11
* 数据库管理工具
*/
object DbManager {
//数据库名
private const val dbName: String = "zroom"
//懒加载创建数据库
val db: ZRoomDB by lazy {
Room.databaseBuilder(
App.app.applicationContext, ZRoomDB::class.java, dbName
).allowMainThreadQueries()//允许在主线程操作
.addCallback(DbCreateCallBack)//增加回调监听
.addMigrations()//增加数据库迁移
.build()
}
private object DbCreateCallBack : RoomDatabase.Callback() {
//第一次创建数据库时调用
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.e("TAG", "first onCreate db version: " + db.version)
}
}
}
使用方法
class MainActivity : AppCompatActivity() {
private val TagL = MainActivity::class.java.simpleName
private lateinit var queryBtn: Button
private lateinit var insertBtn: Button
private lateinit var updateBtn: Button
private lateinit var deleteBtn: Button
private lateinit var resultRecycle: RecyclerView
private var list = mutableListOf<User>()
var userDao: UserDao = DbManager.db.userDao()
private val userAdapter by lazy {
UserAdapter(R.layout.user_item_layout)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findVbId()
}
private fun findVbId() {
queryBtn = findViewById(R.id.query)
insertBtn = findViewById(R.id.insert)
updateBtn = findViewById(R.id.update)
deleteBtn = findViewById(R.id.delete)
resultRecycle = findViewById(R.id.result_recycle)
resultRecycle.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
resultRecycle.adapter = userAdapter
userAdapter.addChildClickViewIds(R.id.item_delete, R.id.item_modify)
queryBtn.setOnClickListener { query() }
insertBtn.setOnClickListener { insertSingle() }
deleteBtn.setOnClickListener { delete() }
updateBtn.setOnClickListener { update() }
userAdapter.setOnItemChildClickListener { _, view, position ->
when (view.id) {
R.id.item_delete -> singleDel(list[position])
R.id.item_modify -> singleModify(list[position])
}
}
insertAll()
}
/**
* 查询
*/
private fun query() {
list = userDao.queryAllUser()
Log.e(TagL, list.toString())
userAdapter.setList(list)
}
/**
* 默认插入批量数据
*/
private fun insertAll() {
runBlocking {
if (userDao.queryAllUser().size == 0) {
val mutableList: MutableList<User> = mutableListOf()
for (a in 1..3) {
val user = User("张三$a", 20 + a, "贵阳市观山湖区$a", "")
mutableList.add(user)
}
userDao.addBatchUser(mutableList)
ToastUtil.show("批量新增数据成功")
}
query()
}
}
/**
* 插入单条数据
*/
private fun insertSingle() {
val age = Random.nextInt(20, 40)
val user = User("小二", age, "贵阳市观山湖区", "")
userDao.addUser(user)
ToastUtil.show("新增一条数据成功")
query()
}
/**
* 删除表里的所有数据
*/
private fun delete() {
userDao.deleteAllUser()
ToastUtil.show("删除所有数据成功")
query()
}
/**
* 更新所有数据
*/
private fun update() {
userDao.updateAll()
ToastUtil.show("更新表里所有年龄数据成功")
query()
}
/**
* 删除loginUser表里的指定删除某一个
*/
private fun singleDel(singleUser: User) {
userDao.deleteSingle(singleUser)
ToastUtil.show("删除单条数据成功")
query()
}
/**
* 修改数据表里某一个对象的字段值
*/
private fun singleModify(user: User) {
user.aliasName = "修改的" + user.aliasName
user.age = 100
user.ads = "修改的地址白云区"
userDao.updateUser(user)
ToastUtil.show("更新单条数据成功")
list.clear()
query()
}
}
数据库升级
- Room 同时支持自动和手动方式进行增量迁移
- *注:Room 在 2.4.0-alpha01 及更高版本中支持自动迁移。如果您的应用使用的是较低版本的 Room,则必须手动定义迁移。
1、手动迁移
- 在实体类User里新增 字段gender
/**
* Author: zqf
* Date: 2022/05/11
* 数据实体
* TODO
* 1、@Entity:Room实体类注解 ---> 默认情况下,Room 将【类名称】用作数据库【表名称】
* 注:如果您希望【数据库表】具有不同的名称,请设置 @Entity 注解的 tableName 属性
* 2、PrimaryKey: 主键( autoGenerate = true 主键自增 ),作用:唯一标识相应数据库表中的每一行
* 3、@ColumnInfo:数据库表字段---> 默认情况下,使用【字段名称】作为数据库中的【列名称】
* 注:如果您希望【数据表里的列】具有不同的名称,请将 @ColumnInfo 注解添加到该字段并设置 name 属性
* 4、Ignore: 默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果您不想保留该字段,则可以使用 @Ignore 为字段添加注解
*/
@Entity(tableName = "loginUser")
data class User(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
@ColumnInfo(name = "name")
var aliasName: String = "",
var age: Int = 0,
var ads: String = "",
@Ignore
var avatar: String = "",
//数据库升级时测试的 新增字段
var gender: Int = 0
) {
constructor(aliasName: String, age: Int, ads: String, avatar: String) : this() {
this.aliasName = aliasName
this.age = age
this.ads = ads
this.avatar = avatar
}
}
- 1)创建 Migration 类,版本从v1—>v2,添加了‘gender’字段 默认值为1
- 2)SQL语句:
2.1)数据库表里增加字段
ALTER TABLE loginUser ADD gender INTEGER Default 1 not null
2.2)数据库新增表
CREATE TABLE Car (id INTEGER, name TEXT, PRIMARY KEY(id))
/**
* 数据库升级
*/
private object ZMigration : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
Log.e(TagL, "执行数据库升级: ")
//loginUser表中增加字段gender
database.execSQL("ALTER TABLE loginUser ADD gender INTEGER Default 1 not null")
//新建汽车数据表
//database.exceSQL("CREATE TABLE Car (id INTEGER, name TEXT, PRIMARY KEY(id))")
}
}
//懒加载创建数据库
//懒加载创建数据库
val db: ZRoomDB by lazy {
Room.databaseBuilder(
App.app.applicationContext, ZRoomDB::class.java, dbName
).allowMainThreadQueries()//允许在主线程操作
.addCallback(DbCreateCallBack)//增加回调监听
.addMigrations(ZMigration)//增加数据库迁移
.build()
}
- 修改Database version版本为 2,依次调整
@Database(entities = [User::class], version = 2, exportSchema = false)
abstract class ZRoomDB : RoomDatabase() {
//创建userDao
abstract fun userDao(): UserDao
}
执行结果:
更多推荐
Android Room 数据库最佳入门教程
发布评论