2024-02-28
Kotlin & 客户端
00

目录

1 依赖
2 定义实体类
3 定义数据访问对象(DAO)
4 定义数据库类
5 在应用中通过Room访问数据
* 通过App Inspection调试应用中的数据库

Room框架是谷歌官方开发框架Jetpack的其中一部分,主要目的是简化开发者访问应用自身的SQLite数据库的步骤。

官方对Room库的说明说明:

Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。具体来说,Room 具有以下优势:

  1. 提供针对 SQL 查询的编译时验证。
  2. 提供方便注解,可最大限度减少重复和容易出错的样板代码。
  3. 简化了数据库迁移路径。

出于这些方面的考虑,我们强烈建议您使用 Room,而不是直接使用 SQLite API。

Room库的架构示意图:

image.png

1 依赖

groovy
dependencies { def room_version = "2.6.1" // room版本 implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" // To use Kotlin annotation processing tool (kapt) kapt "androidx.room:room-compiler:$room_version" // To use Kotlin Symbol Processing (KSP) ksp "androidx.room:room-compiler:$room_version" // optional - RxJava2 support for Room implementation "androidx.room:room-rxjava2:$room_version" // optional - RxJava3 support for Room implementation "androidx.room:room-rxjava3:$room_version" // optional - Guava support for Room, including Optional and ListenableFuture implementation "androidx.room:room-guava:$room_version" // optional - Test helpers testImplementation "androidx.room:room-testing:$room_version" // optional - Paging 3 Integration implementation "androidx.room:room-paging:$room_version" }

2 定义实体类

在Room中,一个实体即为一个数据类,对应一个表中的一条记录。因此一个实体类能够对应一个表的结构。

写法示例如下:

kotlin
/** * 单个文件版本信息 * * @property rowid 主键Id * @property fileId 文件Id * @property filePath 文件具体路径 * @property dateTime 文件更新时间 * @property version 文件版本 */ // @Fts4 该注解使一个实体能够支持全文搜索 但该注解不支持外键 @Entity( tableName = "FileVersionInfo", // 实体注解 声明表名 foreignKeys = [ForeignKey( // 实体注解 声明外键 外键可以有多个 entity = FileEntity::class, // 主表对应实体 childColumns = ["fileId"], // 从表的字段 parentColumns = ["rowid"], // 主表中要依赖的具体字段 onUpdate = ForeignKey.CASCADE, // 更新策略 onDelete = ForeignKey.CASCADE // 删除策略 )] ) data class FileVersionEntity ( @PrimaryKey(autoGenerate = true) // 声明主键 val rowid: Int = 0, // 文件Id @ColumnInfo(name = "fileId") // 声明字段 val fileId: Int, // 文件路径 @ColumnInfo(name = "filePath") val filePath: String, // 文件存储日期 @ColumnInfo(name = "dateTime", defaultValue = "DATETIME") val dateTime: String, // 文件版本 @ColumnInfo(name = "version") val version: Long ) /** * 单个文件信息 * * @property rowid 主键Id * @property fileName 文件名 * @property fileIncidentId 文件关联事件Id * @property fileTag 文件Tag列表 * @property fileUpdateDateTime 文件最新更新日期 * @property fileLatestVersion 文件最新版本 * @property fileComment 文件说明 * @property fileHash 文件最新版本Hash值 */ //@Fts4 @Entity( tableName = "FileInfo", foreignKeys = [ForeignKey( entity = IncidentEntity::class, childColumns = ["fileIncidentId"], parentColumns = ["rowid"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE )] ) data class FileEntity( @PrimaryKey(autoGenerate = true) val rowid: Int = 0, @ColumnInfo(name = "fileName") val fileName: String, @ColumnInfo(name = "fileIncidentId") val fileIncidentId: Int, @ColumnInfo(name = "fileTag") val fileTag: String, @ColumnInfo(name = "fileUpdateDateTime", defaultValue = "DATETIME") val fileUpdateDateTime: String, @ColumnInfo(name = "fileLatestVersion") val fileLatestVersion: Int, @ColumnInfo(name = "fileComment") val fileComment: String, @ColumnInfo(name = "fileHash") val fileHash: String, ) { @Ignore // Ignore注解可以使得room根据实体建表时忽略该字段 val fileVersionInfo: List<FileVersionEntity>? = null // Entity所需要的DataClass的构造方法只能和表的字段互相匹配 因此需要Ignore的字段不能放在构造方法中 } /** * 单个事件信息 * * @property rowid 主键Id * @property incidentName 事件名 * @property incidentComment 事件说明 */ @Entity(tableName = "IncidentInfo") data class IncidentEntity( @PrimaryKey(autoGenerate = true) val rowid: Int = 0, @ColumnInfo(name = "incidentName") val incidentName: String, @ColumnInfo(name = "incidentComment") val incidentComment: String, ) { @Ignore val incidentFileInfo: List<FileEntity>? = null }

3 定义数据访问对象(DAO)

在这里只需要定义DAO接口即可,在接口中的抽象方法声明方法要执行的SQL增删改查操作,其余的代码Room会自动生成。

写法示例如下:

kotlin

4 定义数据库类

数据库类定义了数据库的配置,并且作为应用对SQLite数据库的主要访问点。该数据库类必须是抽象类,必须带有@Database注解,并且对于与该数据库关联的每个DAO类,该类必须定义一个空参数的抽象方法,并返回DAO类的实例。

写法示例如下:

kotlin
/** * 数据库类 通过getInstance()获取实例 * */ @Database( entities = [FileVersionEntity::class, FileEntity::class, IncidentEntity::class], version = 1 ) // Database注解 声明数据库 abstract class FileDatabase: RoomDatabase() { // 这些获取DAO实例的方法必须有 abstract fun fileEntityDAO(): FileEntityDAO // DAO 这一个数据库里可以有多个DAO abstract fun incidentEntityDAO(): IncidentEntityDAO abstract fun fileVersionInfoDAO(): FileVersionInfoDAO // 伴生对象 kotlin的静态方法的写法 companion object { private var INSTANCE: FileDatabase? = null /** * 获取数据库实例 (单例模式) * * @param context 上下文 * @return 数据库实例 */ fun getInstance(context: Context): FileDatabase { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder( context.applicationContext, FileDatabase::class.java, "FileReceiveActivity" ).build() } return INSTANCE as FileDatabase // 转型 } } }

5 在应用中通过Room访问数据

首先必须在应用中获取数据库类和DAO类的实例,之后通过实例在协程中获取数据,再在主线程上更新UI。

* 通过App Inspection调试应用中的数据库

本文作者:御坂19327号

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!