Room概念与基础使用踩坑
安装配置
请注意我配置的详尽步骤,不然后续出错别怪我
官网提供了详尽的可安装依赖:https://developer.android.google.cn/training/data-storage/room?hl=zh-cn
下面所有操作均在 build.gradle(module:app)
中!
第一步,添加 kapt 插件
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
// 添加kapt插件
id 'kotlin-kapt'
}
第二步,添加完整的 room 依赖
请注意,特别是对于 compose 开发,依赖第二条是必须的!否则直接无法编译并报错!
dependencies {
def room_version = "2.2.0"
implementation("androidx.room:room-runtime:$room_version")
kapt "androidx.room:room-compiler:$room_version"
}
room 版本不要选的太高,譬如你当前项目支持的最低 android 版本为 8.0,那么你直接上最新版 2.5.0 的 room,那直接就报错没什么可说的
概念速通
官方教程:https://developer.android.com/codelabs/kotlin-android-training-room-database?hl=zh_cn#0
创建并调用数据库我们只需要三步
- 创建实体类 entity
- 创建数据访问对象 DAO
- 创建数据库单例
Entity
实体使用一个数据类定义
现定义实体类文件 User.kt
请直接看注释
// 实体类均需使用@Entity注解
// 按照官方建议必须定义表名tableName
@Entity(tableName = "user_table")
data class User(
// 主键注解@PrimaryKey
// autoGenerate自增长
@PrimaryKey(autoGenerate = true)
val uid: Int=0,
// 其他键注解@ColumnInfo
// username是存储到数据表的键名
// userName是我们开发中使用的变量名
@ColumnInfo(name = "username")
val userName: String
)
易错点:
如果我们设置了主键且使其自增长,则必须为其添加一个初始值,否则我们调用该实体类时依然需要填写主键的值
DAO
数据访问对象是一个接口
Room 已经为我们准备了 insert 和 delete 接口,我们仅需传入对应的实体类即可让 Room 自动生成对应的 SQL 语法并执行
而其他的语法则全部使用 Query 接口自己写
定义 DAO 文件 UserDao.kt
// DAO注解不可少
@Dao
interface UserDao{
// 插入数据
@Insert
fun insert(user:User)
// 删除数据
@Delete
fun delete(user: User)
// 查询数据
// 这里是查询所有的数据,所以使用List
@Query("select * from user_table")
fun getAll():List<User>
}
Database
下方给出的初始化数据库的抽象类模板是基本固定的,可以直接 cv 拿去用!
数据库目前需要两个关键点:
- 保证单例,即数据库仅实例化一次
- 保证数据库存在时可以拿到数据,不存在时可以自行创建
// 第一步,定义database注解
// 1. entities用到的实体类
// 2. version数据库版本,必须定义,且每次更新数据库都需要修改版本号
// 3. exportSchema是否记录数据库版本
@Database(
entities = [User::class],
version = 1,
exportSchema = false
)
// 继承RoomDatabase
abstract class UserDatabase : RoomDatabase() {
// 第二步:抽象方法userDao
abstract fun userDao(): UserDao
// 第三步:享元实现,保证数据库必须是单例!
// 保证数据库在被实例化时必须是存在的(若不存在就创建后在返回)
companion object {
@Volatile
private var INSTANCE: UserDatabase? = null
fun getInstance(context: Context) =
INSTANCE?: synchronized(this){
// 创建数据库(若数据库不存在)
INSTANCE?:Room.databaseBuilder(
// 上下文
context,
// 欲创建的数据库类
UserDatabase::class.java,
// 数据库名字
"user_database"
)
.fallbackToDestructiveMigration()
.allowMainThreadQueries() // 保证可以在主线程被调用
.build()
}
}
}
开发踩坑
保证仅一次初始化
如果你不愿意拆分出一个单文件用来初始化数据库,而直接在主类中使用它,那么请保证仅初始化一次数据库!
// 全局设置MainActivity上下文
lateinit var mainContext: MainActivity
// 设置全局DAO
lateinit var db: UserDao
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 指定上下文
mainContext = this
// 通过当前主类上下文实例化对应的数据库,并获取DAO
db = UserDatabase.getInstance(mainContext).userDao()
setContent {
...
}
}
}
操作在线程内
利用 kotlin 语法糖 thread,保证所有的数据库操作都写在里面
thread {
db.insert(User(userName = content))
}
相关文章
- Kubernetes基础概念
- 信息安全基础概念原理
- 10 个高级 SQL 概念
- DAPP智能合约系统开发技术概念讲解方案
- 隐私计算FATE-核心概念与单机部署指南
- 还不了解堆栈和队列吗?数据结构最基础、最重要的概念必须掌握!
- JavaScript 入门基础 / 概念介绍(一)
- react高阶组件概念与简单使用
- 系统分析师真题2020试卷相关概念一
- 15分钟掌握Elasticsearch 8大核心概念与基础用法
- 优思学院|零质量控制是什么概念?
- SDK设计与封装:从基础概念入门到架构设计落地笔记
- salesforce零基础学习(一百二十八)Durable Id获取以及相关概念浅入浅出
- 【集合论】集合概念与关系 ( 真子集 | 空集 | 全集 | 幂集 | 集合元素个数 | 求幂集步骤 )
- 【OpenGL】九、OpenGL 绘制基础 ( OpenGL 状态机概念 | OpenGL 矩阵概念 )
- 【Git】Git 基础命令 ( Git 版本库概念 | 创建版本库 git init | 克隆版本库 git clone )
- 【Linux 内核】调度器 ① ( 调度器概念 | 调度器目的 | 调度器主要工作 | 调度器位置 | 进程优先级 | 抢占式调度器 | Linux 进程状态 | Linux 内核进程状态 )
- 【移动端网页布局】移动端网页布局基础概念 ④ ( 物理像素 | 物理像素比 | 代码示例 - 100 像素在 PC浏览器 / 移动端浏览器 显示效果 )
- 【移动端网页布局】移动端网页布局基础概念 ⑧ ( 移动端页面布局方案 | 单独制作的移动端页面 - 主流 | 响应式页面兼容移动端 - 开发难度较大 )
- 【移动端网页布局】移动端网页布局基础概念 ⑦ ( 在 PhotoShop 中使用 Cutterman 切二倍图 | 使用二倍图作为背景图像 )
- PHP-基础语法-变量的概念和使用(一)
- Java线程的概念:什么是线程?
- 学习Linux基础知识:重要概念和实践技能(linux基础课程)
- MySQL数据库的一瞥:快速把握基础概念(mysql数据库快照)
- Redis基础概念与使用指南(什么是redis怎么使用)
- 深入浅出Oracle序列一种特殊的主键生成机制(oracle中序列的概念)
- C#委托所蕴含的函数指针概念详细解析
- Cocos2d-x3.x入门教程(一):基础概念