当前位置: 首页 > news >正文

Android Room数据库使用介绍

1.简介


Room是Google提供的Android架构组件之一,旨在简化数据库操作。它是SQLite的一个抽象层,提供了更易用和安全的API。

Room的总体架构:
在这里插入图片描述

2.Room数据库的基础概念


Entity

Entity是Room中的数据表,每个Entity类对应一个SQLite表。

DAO (Data Access Object)

DAO是用于访问数据库的方法接口,定义了与数据库交互的操作。

Database

Database是Room数据库的抽象类,持有数据库并作为数据访问的主要入口点。

3.Room数据库的配置


添加依赖

在build.gradle文件中添加Room的依赖项。

dependencies {implementation "androidx.room:room-runtime:2.5.0"annotationProcessor "androidx.room:room-compiler:2.5.0"// 可选 - 支持Lifecycle的LiveDataimplementation "androidx.room:room-ktx:2.5.0"
}

定义Entity

// tableName 指定了数据库中对应的表名为 "users"。如果不指定,默认使用类名作为表名
@Entity(tableName = "users")
data class User(// 使用默认值 0,autoGenerate = true 表示自动生成主键@PrimaryKey(autoGenerate = true)val id: Int = 0, // 如果不使用 @ColumnInfo 注解,默认情况下 Room 将使用属性名作为数据库中的列名@ColumnInfo(name = "first_name")val firstName: String,@ColumnInfo(name = "last_name")val lastName: String
)

创建DAO

@Dao
interface UserDao {@Insertfun insert(user: User)//@Insert(onConflict = OnConflictStrategy.REPLACE):用于定义插入操作,并指定了替换策略为 OnConflictStrategy.REPLACE。这意味着如果插入的数据在数据库中已存在(根据主键判断),则旧数据会被新数据替换。@Insert(onConflict = OnConflictStrategy.REPLACE)fun insert(user: User)@Query("SELECT * FROM users WHERE id = :id")fun getUserById(id: Int): User?@Updatefun update(user: User)@Deletefun delete(user: User)
}

tips: OnConflictStrategy.REPLACE:如果插入的数据在数据库中已存在(即主键冲突),则会替换原有的数据。

创建Database

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserRoomDatabase : RoomDatabase() {abstract fun userDao(): UserDaocompanion object {@Volatileprivate var INSTANCE: ItemRoomDatabase? = nullfun getDatabase(context: Context): UserRoomDatabase {return INSTANCE ?: synchronized(this) {val instance = Room.databaseBuilder(context.applicationContext,UserRoomDatabase::class.java,"user_database").fallbackToDestructiveMigration().build()INSTANCE = instanceinstance}}}
}

tips:注意fallbackToDestructiveMigration() 一般在调试中使用,如果你修改了数据库表结构,而没有升级数据库通常程序再次运行会报错,使用fallbackToDestructiveMigration() 表示将老的数据库表结构和数据全部删除,使用新的结构,允许破坏性迁移,即销毁旧数据库并创建新数据库。

初始化数据库

val db: UserRoomDatabase by lazy { UserRoomDatabase.getDatabase(this) }

4.Room数据库的使用


插入数据

val user = User().apply {firstName = "John"lastName = "Doe"
}
db.userDao().insert(user)

查询数据

val user = db.userDao().getUserById(1)

更新数据

user.lastName = "Smith"
db.userDao().update(user)

删除数据

db.userDao().delete(user)

5.Room数据库的高级特性


使用LiveData和Flow

@Query("SELECT * FROM users")
LiveData<List<User>> getAllUsers();@Query("SELECT * FROM users")
Flow<List<User>> getAllUsersFlow();

数据库迁移

@Database(entities = [User::class], version = 2, exportSchema = false)
abstract class UserRoomDatabase : RoomDatabase() {abstract fun userDao(): UserDaocompanion object {@Volatileprivate var INSTANCE: ItemRoomDatabase? = null//迁移代码 用于从版本 1 迁移到版本 2。val MIGRATION_1_2: Migration = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//为users表增加age属性database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER")}}fun getDatabase(context: Context): UserRoomDatabase {return INSTANCE ?: synchronized(this) {val instance = Room.databaseBuilder(context.applicationContext,UserRoomDatabase::class.java,"user_database").addMigrations(AppDatabase.MIGRATION_1_2) //在此处添加.build()INSTANCE = instanceinstance}}}
}

使用TypeConverters

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class UserRoomDatabase: RoomDatabase() {abstract fun userDao(): UserDao...
}object Converters {@TypeConverter@JvmStaticfun fromTimestamp(value: Long?): Date? {return value?.let { Date(it) }}@TypeConverter@JvmStaticfun dateToTimestamp(date: Date?): Long? {return date?.time}
}

User 中增加 Date类型 createdAt属性

@Entity(tableName = "users")
data class User(@PrimaryKey(autoGenerate = true)val id: Long = 0,val name: String,val createdAt: Date
)

说明:

  • 类型转换器 (Converters):使用 Room 持久化库时,有时需要在数据库存储和应用程序中的对象之间进行转换。例如,将 Date 对象存储为 Long 类型的时间戳或从时间戳恢复为 Date 对象,其他对象类型同理。
  • @TypeConverter 注解:用于标记类型转换器的方法,告诉 Room 如何在持久化过程中执行对象到数据库兼容格式之间的转换。
  • @Database 和 @TypeConverters 注解:用于在 UserRoomDatabase中指定数据库的配置,包括数据库版本号和要使用的类型转换器。

示例:

class Converters {//enum 类型@TypeConverterfun toDownloadStatus(value: String): DownloadStatus = enumValueOf(value)@TypeConverterfun fromDownloadStatus(status: DownloadStatus): String = status.name@TypeConverterfun fromHashMap(value: HashMap<Int, Int>): String {val gson = Gson()return gson.toJson(value)}@TypeConverterfun toHashMap(value: String): HashMap<Int, Int> {val gson = Gson()val type = object : TypeToken<HashMap<Int, Int>>() {}.typereturn gson.fromJson(value, type)}//自定义对象@TypeConverterfun fromDownloadException(downloadException: DownloadException?): String? {if (downloadException == null) {return null}return Gson().toJson(downloadException)}@TypeConverterfun toDownloadException(value: String?): DownloadException? {if (value == null) {return null}val type = object : TypeToken<DownloadException>() {}.typereturn Gson().fromJson(value, type)}
}

6. Room数据库的实践


线程管理

确保数据库操作在后台线程中完成,在主线程中操作数据库会报错。

Executors.newSingleThreadExecutor().execute {db.userDao().insert(user)
}

数据库性能优化

  • 使用批量插入和更新。
  • 使用索引提高查询性能。

处理大型数据集

使用分页库(Paging Library)处理大型数据集。

@Query("SELECT * FROM users ORDER BY id ASC")
fun getAllUsers(): PagingSource<Int, User>

使用分页库需要增加依赖

implementation "androidx.paging:paging-runtime-ktx:$paging_version"


后面单独写篇文章介绍分页库使用,敬请期待…

相关文章:

  • SpringBoot3 整合 Mybatis 完整版
  • 【MySQL】分库分表
  • USB - 常用开发工具
  • C++ -- 红黑树的基本操作
  • 从零开始精通Onvif之图片抓拍
  • Mybatis --- 动态SQL 和数据库连接池
  • docker Pulling fs layer 含义
  • DeepSpeed Monitoring Comm. Logging
  • 速盾:什么是高防CDN?有什么优势?
  • 网络安全复习笔记
  • 入门Rabbitmq
  • QT中出现ASSERT failure in QList::at: “index out of range”的情况和解决办法
  • 全面解析AdaBoost:多分类、逻辑回归与混合分类器的实现
  • 基于DPU的云原生裸金属服务快速部署及存储解决方案
  • Jupyter Notebook 中 %run 魔法命令
  • [Vue CLI 3] 配置解析之 css.extract
  • 2017届校招提前批面试回顾
  • ComponentOne 2017 V2版本正式发布
  • Druid 在有赞的实践
  • gops —— Go 程序诊断分析工具
  • httpie使用详解
  • IDEA常用插件整理
  • Javascript 原型链
  • java中具有继承关系的类及其对象初始化顺序
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • Python 基础起步 (十) 什么叫函数?
  • sessionStorage和localStorage
  • SQLServer之创建显式事务
  • SQLServer之索引简介
  • Swift 中的尾递归和蹦床
  • TCP拥塞控制
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • windows下使用nginx调试简介
  • 阿里研究院入选中国企业智库系统影响力榜
  • 番外篇1:在Windows环境下安装JDK
  • - 概述 - 《设计模式(极简c++版)》
  • 记一次删除Git记录中的大文件的过程
  • 新版博客前端前瞻
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 云大使推广中的常见热门问题
  • Spring Batch JSON 支持
  • 阿里云重庆大学大数据训练营落地分享
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #pragma pack(1)
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (13)Hive调优——动态分区导致的小文件问题
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (vue)el-tabs选中最后一项后更新数据后无法展开
  • (二) 初入MySQL 【数据库管理】
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (四)activit5.23.0修复跟踪高亮显示BUG