带你认识和使用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



相关文章
|
Java API 调度
Kotlin 中的suspend 关键字
Kotlin 中的suspend 关键字
407 0
|
负载均衡 Java 应用服务中间件
Caddy Web服务器深度解析与对比:Caddy vs. Nginx vs. Apache
Caddy Web服务器深度解析与对比:Caddy vs. Nginx vs. Apache
1472 0
|
关系型数据库 MySQL 数据安全/隐私保护
允许远程链接mysql,开放3306端口
允许远程链接mysql,开放3306端口
允许远程链接mysql,开放3306端口
|
12月前
|
设计模式 网络协议 Java
06.动态代理设计模式
本文详细介绍了动态代理设计模式,包括其必要性、概念、实现方式及案例分析。动态代理允许在运行时动态创建代理对象,增强代码复用性和灵活性,减少类膨胀。文章通过对比静态代理,深入解析了动态代理的实现机制,如基于接口和类的动态代理,以及其在Retrofit中的应用。同时,讨论了动态代理的优势和潜在问题,如性能开销和调试难度。最后,提供了丰富的学习资源链接,帮助读者进一步理解和掌握动态代理。
153 1
|
C++
C++中的封装、继承与多态:深入理解与应用
C++中的封装、继承与多态:深入理解与应用
362 1
|
11月前
|
机器学习/深度学习 人工智能 自然语言处理
AI与法律行业:智能法律咨询
在科技飞速发展的今天,人工智能(AI)正逐渐渗透到法律行业,特别是在智能法律咨询领域。本文探讨了AI在智能法律咨询中的应用现状、优势及挑战,并展望了其未来发展前景。AI技术通过大数据、自然语言处理等手段,提供高效、便捷、低成本且个性化的法律服务,但同时也面临数据隐私、法律伦理等问题。未来,AI将在技术升级、政策推动和融合创新中,为用户提供更加优质、便捷的法律服务。
|
数据挖掘 OLAP OLTP
深入解析:OLTP与OLAP的区别与联系
【8月更文挑战第31天】
2801 0
|
存储 前端开发 JavaScript
状态管理(State Management):构建复杂应用的关键要素
在现代应用程序开发中,状态管理是一个至关重要的概念,它用于管理应用程序的数据和状态。无论您是开发Web应用、移动应用还是桌面应用,都需要有效的状态管理来确保应用程序的可维护性和可扩展性。在本博客中,我们将深入研究状态管理的定义、原则、工具和最佳实践,以及如何充分利用状态管理来构建复杂的应用程序。
892 0
|
Kubernetes Cloud Native Java
Docker打包制作openoffice镜像(Dockerfile方式),并处理中文乱码
鉴于目前,云原生k8s的部署方式,越来越广泛。那我们也应该要使用docker的方式部署openoffice。 这个部署的第一步,就是要有一个docker镜像,那我们今天就来讲讲,如何制作openoffice的docker镜像包。 当然啦,openoffice的docker镜像包,我们可以从docker hub仓库,直接拉别人制作好的镜像包。
1066 0
|
机器学习/深度学习 数据可视化 算法
数据分析基础:Python 与统计学
在当今数据驱动的世界中,数据分析已成为各个领域的关键技能。Python 作为一种强大的编程语言,结合了丰富的数据分析库,使其成为数据分析的首选工具之一。同时,统计学作为数据分析的理论基础,提供了一套方法来理解和解释数据。本文将介绍 Python 在数据分析中的应用,以及统计学在数据分析中的重要性。