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的LiveData
    implementation "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 {
    @Insert
    fun 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?

    @Update
    fun update(user: User)

    @Delete
    fun delete(user: User)
}

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

创建Database

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserRoomDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        @Volatile
        private var INSTANCE: ItemRoomDatabase? = null

        fun getDatabase(context: Context): UserRoomDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    UserRoomDatabase::class.java,
                    "user_database"
                )
                    .fallbackToDestructiveMigration()
                    .build()
                INSTANCE = instance
                instance
            }
        }
    }
}

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(): UserDao

    companion object {
        @Volatile
        private 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 = instance
                instance
            }
        }
    }
}

使用TypeConverters

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class UserRoomDatabase: RoomDatabase() {
    abstract fun userDao(): UserDao
    ...
}

object Converters {
    @TypeConverter
    @JvmStatic
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    @JvmStatic
    fun 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 类型
    @TypeConverter
    fun toDownloadStatus(value: String): DownloadStatus = enumValueOf(value)

    @TypeConverter
    fun fromDownloadStatus(status: DownloadStatus): String = status.name


    @TypeConverter
    fun fromHashMap(value: HashMap<Int, Int>): String {
        val gson = Gson()
        return gson.toJson(value)
    }

    @TypeConverter
    fun toHashMap(value: String): HashMap<Int, Int> {
        val gson = Gson()
        val type = object : TypeToken<HashMap<Int, Int>>() {}.type
        return gson.fromJson(value, type)
    }

    //自定义对象
    @TypeConverter
    fun fromDownloadException(downloadException: DownloadException?): String? {
        if (downloadException == null) {
            return null
        }
        return Gson().toJson(downloadException)
    }

    @TypeConverter
    fun toDownloadException(value: String?): DownloadException? {
        if (value == null) {
            return null
        }
        val type = object : TypeToken<DownloadException>() {}.type
        return 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"


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/707761.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

神经网络字符分类

按照题目要求修改了多层感知机 题目将图片的每个点作为输入&#xff0c;其中大小为28*28&#xff0c;中间有两个大小为100的隐藏层&#xff0c;激活函数是relu&#xff0c;然后输出大小是10&#xff0c;激活函数是softmax 优化器是Adam&#xff0c;结合了AdaGrad和RMSProp算法…

【elementui源码解析】如何实现自动渲染md文档-第三篇

目录 1.前言 2.webpack.demo.js 3.markdown文档 4.fence.js 1&#xff09;tokens 2&#xff09;::: 3&#xff09; 5.containers.js 1&#xff09;markdown-it-container 2&#xff09;md.use() 3&#xff09;代码逻辑 4&#xff09;containers小结 6.congfig.js …

Stable Diffusion【光影文字】:绚丽光影,文字与城市夜景的光影之约

今天我们我们结合城市夜景背景来看一下光影文字的效果&#xff0c;我们先来看一下效果图。 一. 字融城市夜景制作光影文字方法 【第一步】&#xff1a;制作底图这里制作底图使用黑底白字。我们使用美图秀秀制作一个"小梁子"字的底图。 字体&#xff1a;默认字体 图…

怕怕怕怕怕怕怕怕怕怕

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

期望14K,某小公司java社招面试经历

面经哥只做互联网社招面试经历分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥 面试的是一家几百人的公司&#xff0c;基本面试的考察有八股文&#xff0c;也有按照项目问你的&#xff0c;总的来说比较全面吧 1、java代理模式 …

郑州企业资信评价资质:工程咨询单位专业资信申报材料清单

在郑州企业申请工程咨询单位专业资信评价资质时&#xff0c;需要准备一系列详细的申报材料。以下是根据参考文章中的相关数字和信息&#xff0c;清晰、分点表示和归纳的工程咨询单位专业资信申报材料清单&#xff1a; 一、基础材料 企业法人营业执照&#xff1a;提供企业法人营…

统计nginx访问日志前十名

可用下面五种方式来查看&#xff1a; 1. grep -oP ‘^\S’ access.log |sort -rn |uniq -c |sort -rn |head 命令详细讲解&#xff1a; grep: 是一个文本搜索工具&#xff0c;允许你在文件中搜索特定的模式。 -o: 只输出匹配的部分&#xff0c;而不是整行。 -P: 使用Perl兼容的…

Introducing Index-1.9B

简介 大家好&#xff0c;今天我们很高兴首次发布Index系列模型中的轻量版本&#xff1a;Index-1.9B系列 本次开源的Index-1.9B 系列包含以下模型&#xff1a; Index-1.9B base : 基座模型&#xff0c;具有 19亿 非词嵌入参数量&#xff0c;在2.8T 中英文为主的语料上预训练&…

【JavaEE精炼宝库】多线程(5)单例模式 | 指令重排序 | 阻塞队列

目录 一、单例模式&#xff1a; 1.1 饿汉模式&#xff1a; 1.2 懒汉模式&#xff1a; 1.2.1 线程安全的懒汉模式&#xff1a; 1.2.2 线程安全的懒汉模式的优化&#xff1a; 二、指令重排序 三、阻塞队列 3.1 阻塞队列的概念&#xff1a; 3.2 生产者消费者模型&#xf…

公司面试题总结(五)

25.谈一谈箭头函数与普通函数的区别&#xff0c;箭头函数主要解决什么问题&#xff1f; 箭头函数与普通函数的区别&#xff1a; ⚫ 语法简洁性&#xff1a; ◼ 箭头函数使用>符号定义&#xff0c;省略了 function 关键字&#xff0c;使得语法更为紧凑。 ◼ 对于单行函…

剖析框架代码结构的系统方法(下)

当面对Dubbo、Spring Cloud、Mybatis等开源框架时,我们可以采用一定的系统性的方法来快速把握它们的代码结构。这些系统方法包括对架构演进过程、核心执行流程、基础架构组成和可扩展性设计等维度的讨论。 在上一讲中,我们已经讨论了架构演进过程和核心执行流程这两个系统方法…

【npm】console工具(含胶囊,表格,gif图片)

这是一款控制台花样输出工具 相对丰富的输出方式 文本输出属性值输出胶囊样式输出表格输出图片输出&#xff08;含动图&#xff09; 安装 npm install v_aot引用 import v_aot from "v_aot";字段说明 字段类型属性字符串值字符串类型default 、 primary 、 suc…

深入解析MySQL的层次化设计

一、基础架构 1.连接器 1.会先连接到这个数据库上&#xff0c;这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接 2.用户密码连接成功之后&#xff0c;会从权限表中拿出你的权限&#xff0c;后续操作权限都依赖于此时拿出的权限,这就意味着当链…

Github 2024-06-14 开源项目日报Top10

根据Github Trendings的统计,今日(2024-06-14统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量JavaScript项目2Python项目2非开发语言项目2TypeScript项目1Dart项目1Rust项目1Lua项目1Java项目1Jupyter Notebook项目1从零开始构建你喜爱的技…

代码随想录算法训练营第二十三天|669. 修剪二叉搜索树、 108.将有序数组转换为二叉搜索树、 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 题目链接&#xff1a;669. 修剪二叉搜索树 文档讲解&#xff1a;代码随想录 状态&#xff1a;还可以 思路&#xff1a; 如果节点的值在[low, high]之间&#xff0c;则递归修剪它的左子树和右子树。 节点值小于low&#xff1a;如果节点的值小于low&#xff…

【机器学习】简答

1.什么是机器学习&#xff1f; 机器学习致力于研究如何通过计算的手段&#xff0c;利用经验来改善系统自身的性能。“训练”与“预测”是机器学习的两个过程&#xff0c;“模型”则是过程的中间输出结果&#xff0c;“训练”产生“模型”&#xff0c;“模型”指导 “预测”。计…

数字经济红利惠及全民,从掏钱消费到赚钱消费的转变,你准备好了吗?

伴随科技飞速发展&#xff0c;我们迎来了一个全新的经济时代——数字经济。数字经济以其独特的魅力&#xff0c;正为我们每个人带来前所未有的红利。 那么&#xff0c;面对数字经济的红利&#xff0c;我们是否已经做好了准备&#xff1f;我们又该如何把握这个时代赋予我们的机…

内存卡提示需要格式化?别急,这样拯救你的数据

一、内存卡突然提示需要格式化 在日常生活中&#xff0c;我们经常会使用到内存卡来存储照片、视频、文档等重要数据。然而&#xff0c;有时当我们试图访问内存卡时&#xff0c;却会遭遇一个令人头疼的问题——系统突然提示“内存卡需要格式化”。这意味着我们无法直接读取或写…

不愧是字节,图像算法面试真细致

这本面试宝典是一份专为大四、研三春招和研二暑假实习生准备的珍贵资料。 涵盖了图像算法领域的核心知识和常见面试题&#xff0c;包括卷积神经网络、实例分割算法、目标检测、图像处理等多个方面。不论你是初学者还是有经验的老手&#xff0c;都能从中找到实用的内容。 通过…

自动控制理论---零点和极点、单位脉冲响应

1、实验设备 PC计算机1台&#xff0c;MATLAB软件1套。 2、实验目的 研究四个具有相同极点分布但不同零点分布的二阶系统对单位脉冲响应的影响。绘制各系统的零点和极点分布图。计算并绘制各系统的单位脉冲响应波形。分析零点分布对单位脉冲响应的影响。 3、实验原理说明&am…