带你认识和使用Room|青训营笔记

简介: Room 是 Google jetpack 体系的一个数据库框架,近年来 Google 力推该框架,作为开发者,我们也需拥抱新技术。

何为 Room

Room 是 Google jetpack 体系的一个数据库框架,近年来 Google 力推该框架,作为开发者,我们也需拥抱新技术。

RoomSQLite 的抽象,是为了让 SQLite 更方便Android开发者使用而研发的一个数据库框架

下面引用 Android 开发者指南对 Room 的优势说明

In particular, Room provides the following benefits:

  • Compile-time verification of SQL queries.
  • Convenience annotations that minimize repetitive and error-prone boilerplate code.
  • Streamlined database migration paths.

引用自Save data in a local database using Room  | Android Developers

翻译过来,就是以下三个优势

  1. 会对SQL在编译阶段进行验证
  2. 有方便我们使用的注解,可以大幅度减少重复编写和出错
  3. 数据库更容易迁移
  4. 可以和多种三方库桥接进行异步查询

Room 的使用效率如何

1.webp.jpg

Room 的基本使用

了解完 Room 是什么,还等什么,快速上手 Room

1.webp.jpg

库的导入

要使用 Room ,我们先要在 build.gradle(:app) 里面引入该库

plugins {
    ...
    //if use kapt
    id 'kotlin-kapt'
}
...
dependencies {
    def room_version = "2.4.3"
  //base
    implementation "androidx.room:room-runtime:$room_version"
    // To use Java annotation processing tool 
    annotationProcessor "androidx.room:room-compiler:$room_version"
    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$roomVersion"
    ...
}
复制代码

我们需要引入 Room 的时候,一定需要的是 runtime 库和对应的一个注解处理器 的库,上面的代码我引入了 java 和kotlin 两种类型,实际使用中,我们引入一种就好。注解处理器一定是要引入的,这样子我们才能根据注解在编译期生成对应的实现类。

如果引入的是 kapt,记得要在插件声明处声明对应的插件。

数据实体(Entity)

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true) val uid: Int?,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)
复制代码

作用:用于表示应用的数据库中的表。

上面代码是数据实体类的,我们需要对类写一个 @Entity() 注解,tableName = "users" 是对表的命名,否则表就自动以类名做表名。

接下来我们来看下面的数据变量

@PrimaryKey() 表示的是主键,添加 autoGenerate = true 表示输入的id为空时候,允许自动赋值。每一个表都是需要有一列做主键

@ColumnInfo(name = "first_name") 表示的是为该字段的对应列命名。若是不使用该注解,列名则自动为字段名称

数据访问对象(DAO)

@Dao
interface Dao {
    @Query("SELECT * FROM user")
    fun getAll(): List<User>
    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    fun loadAllByIds(userIds: IntArray): List<User>
    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
            "last_name LIKE :last LIMIT 1")
    fun findByName(first: String, last: String): User
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(vararg users: User)
    @Delete
    fun delete(user: User)
}
复制代码

作用:提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。

上文代码的数据库访问对象,我们写的时候其实就是写一个对应的接口,对接口里面的方法附上相关的注解。然后在代码的编译阶段,就会根据注解生成对应的代码。

上文的代码中我们可以看到,有部分的方法注解里面会用到 SQL 语句,但是有部分就不需要 SQL 语句。这是由于 Room 给我们提供了两种不同的查询方法,一种是自带插入 InsertUpdateDelete的 便捷方法,一种是自己编写 SQL 语句的自定义查询方法

There are two types of DAO methods that define database interactions:

  • Convenience methods that let you insert, update, and delete rows in your database without writing any SQL code.
  • Query methods that let you write your own SQL query to interact with the database.

From Accessing data using Room DAOs  | Android Developers

两种方法配合使用,我们就可以低成本使用且易复用 SQLite 的强大功能了。使用查询方法的前提是我们会 SQL 语法,还不懂的同学,需要先学会 SQL 语法

在线就能用的 SQL 练习平台我给你找好了! - 知乎 (zhihu.com)

数据库类(Database)

@Database(entities = [User::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): Dao
}
复制代码

作用:用于保存数据库并作为应用持久性数据底层连接的主要访问点。

这个类是为建立和保存数据库所使用的,有以下三个要点

  • 新增一个RoomDatabaseabstract子类,需要是抽象类
  • 子类需加注解@Database(entities = [xxx], version = n)entities包含数据实体,将会在这个数据库中创建对应的表,version是数据的版本号
  • 对于与数据库关联的每个DAO类,数据库类必须定义一个无参的抽象方法,并返回DAO类实例

来自:【Android 客户端专场 学习资料二】第四届字节跳动青训营 - 掘金 (juejin.cn)

@Database 该注解包含列出所有与数据库关联的数据实体的 entities 数组。也就是说,当我们有多个表的时候,需要把所有表都置于该注解上边。例如,两个表的时候,entities = [User::class, single::class]

@Database 注解的另一个 version 参数,是为数据库的版本号。当我们要变动数据库的表的时候,如果直接变动,不做迁移(更新),程序是会崩溃的。应用 autoMigrations = [AutoMigration (from = 1, to = 2)] 这个注解参数,可以实现自动的迁移。示例代码如下,更多的迁移方法可以查看指南 Migrating Room databases  | Android Developers

// Database class before the version update.
@Database(
  version = 1,
  entities = [User::class]
)
abstract class AppDatabase : RoomDatabase() {
  ...
}
// Database class after the version update.
@Database(
  version = 2,
  entities = [User::class],
  autoMigrations = [
    AutoMigration (from = 1, to = 2)
  ]
)
abstract class AppDatabase : RoomDatabase() {
  ...
}
复制代码

创建使用数据库

val db = Room.databaseBuilder(
    applicationContext,
    AppDatabase::class.java, "database-name"
).build()
val userDao = db.userDao()
val user1 = User(null,"hhhh","zhang")
val user2 = User(1,"ddd","nishone")
binding.button.setOnClickListener {
    Thread{
        userDao.insertAll(user1,user2)
            list= userDao.getAll()
            if (list != null){
                Log.d(TAG, "onCreate: ${list!![1].firstName}")
            }else{
                Log.d(TAG, "onCreate: ")
            }
    }.start()
}
复制代码

由于数据库的创建和使用都是耗时操作,在开发中,没有使用到多进程的时候,我们谨记要遵循单例模式来创建实例;在调用增上改查时候,我们需要在子线程中来完成这个操作。

注意:如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。每个 RoomDatabase 实例的成本相当高,而您几乎不需要在单个进程中访问多个实例。

如果您的应用在多个进程中运行,请在数据库构建器调用中包含 enableMultiInstanceInvalidation()。这样,如果您在每个进程中都有一个 AppDatabase 实例,可以在一个进程中使共享数据库文件失效,并且这种失效会自动传播到其他进程中 AppDatabase 的实例。

Room 的表关系

日常开发中,我们数据库的表经常要做到和其他的表关联的,各个表直接也都是有关系的。而 Room 自然也提供了关于表联立的用法给我们,要注意的是,它不提供实体直接引用的形式。

关于表的关系,大家请查看官方文档,官方文档有详细的说明。

定义对象之间的关系  | Android 开发者  | Android Developers



相关文章
|
3月前
|
Python
小甲鱼 模块与包上 笔记
小甲鱼 模块与包上 笔记
35 0
|
存储 Java 编译器
与Go的初次见面 | 青训营笔记
与Go的初次见面 | 青训营笔记
64 0
|
前端开发 JavaScript
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
46 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
|
前端开发 JavaScript
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
66 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
|
前端开发 JavaScript
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十九题-call
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十九题-call
78 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十九题-call
|
机器学习/深度学习 人工智能 CDN
初学者必刷题---PTA基础编程题目集第一期
初学者必刷题---PTA基础编程题目集第一期
|
前端开发 JavaScript
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十题-object.freeze
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十题-object.freeze
49 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百六十题-object.freeze
|
前端开发
#yyds干货盘点# 前端歌谣的刷题之路-第一百一十五题-根据包名 在指定空间中创建对象
#yyds干货盘点# 前端歌谣的刷题之路-第一百一十五题-根据包名 在指定空间中创建对象
45 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百一十五题-根据包名 在指定空间中创建对象
|
前端开发
#yyds干货盘点# 前端歌谣的刷题之路-第一百三十二题-定位-z-index
#yyds干货盘点# 前端歌谣的刷题之路-第一百三十二题-定位-z-index
58 0
#yyds干货盘点# 前端歌谣的刷题之路-第一百三十二题-定位-z-index
|
C++ Python
C++入门详细笔记(共八章)(中)
C++入门详细笔记(共八章)
93 0
C++入门详细笔记(共八章)(中)