【Android】Room数据库的简单使用方法

Room数据库的使用方法

目录

  • 1、添加Room数据库的依赖
  • 2、Entity——定义实体类
    • 2.1 定义主键——PrimaryKey
    • 2.2 字段注解——ColumnInfo
  • 3、Dao——定义数据访问对象
  • 4、Database——数据库
    • 4.1 通过回调观察数据库是否创建成功
  • 5、使用时注意点
  • 6、编写异步 DAO 查询
    • 6.1 写异步单次查询
    • 6.2 编写可观察查询

参考文档:
[1] 使用 Room 实体定义数据
[2] 使用 Android Jetpack 的 Room 部分将数据保存到本地数据库。
[3] 实体类介绍
[4] RoomAPI、依赖
[5] 编写异步Dao查询

1、添加Room数据库的依赖

//Room
implementation "androidx.room:room-runtime:2.6.1"
annotationProcessor "androidx.room:room-compiler:2.6.1"//Rxjava
implementation "androidx.room:room-rxjava3:2.6.1"

Room是由三大部分组成的:

  1. Entity:数据库中表对应的Java实体
  2. DAO:操作数据库的方法
  3. Database:创建数据库

2、Entity——定义实体类

@Entity:

  • 用于定义数据库表结构。
  • 包含以下常用属性:
    • tableName: 指定表名。
    • primaryKeys: 指定主键字段。
    • indices: 定义索引。
    • foreignKeys: 定义外键关系

默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。

同样,Room 默认使用字段名称作为数据库中的列名称。

@Entity(tableName = "users")
public class User {@PrimaryKey(autoGenerate = true)public int id;@ColumnInfo(name = "first_name")public String firstName;@ColumnInfo(name = "last_name")public String lastName;
}

2.1 定义主键——PrimaryKey

每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行。

  1. @PrimaryKey:
    • 用于标记主键字段。
    • 包含以下常用属性:
      • autoGenerate: 是否自动生成主键值。
      • 注意:自增主键必须为int型。

2.2 字段注解——ColumnInfo

  1. @ColumnInfo:
    • 用于定义表字段。
    • 包含以下常用属性:
      • name: 指定字段名,也就是表的列名
      • typeAffinity: 指定字段类型。
      • defaultValue:设置默认值,未指定值时的默认值

通过 typeAffinity 属性,可以指定字段的数据类型,如 TEXTINTEGER 等。

📌注意数据需要均为Public


@Entity
public class HistoryData {@PrimaryKey(autoGenerate = true)public int id;@ColumnInfo(typeAffinity = ColumnInfo.TEXT)public LocalDate birthDate;@ColumnInfo(name = "Name")public String name;@ColumnInfo(defaultValue = "18")public int age;}

在这个例子中,birthDate 字段在数据库中会被存储为 TEXT 类型。

3、Dao——定义数据访问对象

常用注解包括:

  1. @Query:
    • 用于定义数据库查询语句。
    • 可以返回 FlowableObservableSingleMaybe 等 RxJava 类型。
  2. @Insert@Update@Delete:
    • 用于定义数据库增、改、删操作。
    • 可以返回 longintvoid 等类型,表示受影响的行数。
@Dao
public interface HistoryDao {/*** 向数据库添加数据** @param data*/@Insertvoid insertData(HistoryData data);/*** 删除数据库所有数据*/@Query("DELETE FROM HistoryData")void deleteDataAll();
}

4、Database——数据库

以下代码定义了用于保存数据库的 HistoryDatabase 类。 HistoryDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。数据库类必须满足以下条件:

  • 该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
  • 该类必须是一个抽象类,用于扩展 RoomDatabase。
  • 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
@Database(entities = HistoryData.class, version = 1)
public abstract class HistoryDatabase extends RoomDatabase {public abstract HistoryDao historyDao();
}

请注意:

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

用法举例:


@Database(entities = HistoryData.class, version = 1)
public abstract class HistoryDatabase extends RoomDatabase {private static volatile HistoryDatabase historyDB = null;//单例模式双检锁public static HistoryDatabase getInstance(Context context) {if (historyDB == null) {synchronized (HistoryDatabase.class) {if (historyDB == null) {historyDB = Room.databaseBuilder(context.getApplicationContext(), HistoryDatabase.class, "location_History").build();}}}return historyDB;}public abstract HistoryDao historyDao();
}

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

用法举例:

@Database(entities = HistoryData.class, version = 1)
public abstract class HistoryDatabase extends RoomDatabase {public static HistoryDatabase getDatabase(Context context) {return Room.databaseBuilder(context.getApplicationContext(),HistoryDatabase.class, "chat_database").enableMultiInstanceInvalidation().build();}public abstract HistoryDao historyDao();
}

4.1 通过回调观察数据库是否创建成功

通过RoomDatabase提供的Callback()回调方法观测数据库状态。

Callback提供了三个回调方法:分别是数据库第一次被创建时调用,数据库打开时调用,数据库被销毁迁移后调用

我们在创建数据库时添加上这个回调方法的实现类即可:

@Database(entities = HistoryData.class, version = 1,exportSchema = false)
public abstract class HistoryDatabase extends RoomDatabase {public abstract HistoryDao historyDao();private static volatile HistoryDatabase historyDB = null;public static HistoryDatabase getInstance(Context context) {if (historyDB == null) {synchronized (HistoryDatabase.class) {if (historyDB == null) {historyDB = Room.databaseBuilder(context, HistoryDatabase.class, "locationHistory").addCallback(roomCallback).build();}}}return historyDB;}// 回调函数,可在数据库创建、打开和关闭时执行操作private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {@Overridepublic void onCreate(@NonNull SupportSQLiteDatabase db) {super.onCreate(db);Log.d("HistoryDatabase", "Database created successfully");}};
}

5、使用时注意点

为防止查询阻止界面,Room 不允许在主线程上访问数据库。 此限制意味着您必须将DAO 查询设为异步。Room 库包含与多个不同框架的集成,以提供异步查询执行功能。


// 创建一个ExecutorService
ExecutorService executor = Executors.newSingleThreadExecutor();// 提交删除操作到ExecutorService中执行
executor.submit(() -> {HistoryData data = new HistoryData();data.setLocationName("天津");HistoryDatabase.getInstance(getContext()).historyDao().insertData(data);//在主线程中更改UIrunOnUiThread(() -> {});});// 关闭ExecutorService
executor.shutdown();

6、编写异步 DAO 查询

Java 与 RxJava

如果您的应用使用 Java 编程语言,则您可以使用 RxJava 框架的专用返回类型编写异步 DAO 方法。Room 支持以下 RxJava 2 返回值类型:

  • 对于单次查询,Room 2.1 及更高版本支持 Completable、Single<T> 和 Maybe<T> 返回值类型。
  • 对于可观察查询,Room 支持 Publisher<T>、Flowable<T> 和 Observable<T> 返回值类型。

此外,Room 2.3 及更高版本支持 RxJava 3。

📌注意:如需将 RxJava 与 Room 搭配使用,您必须在 build.gradle 文件中添加 room-rxjava2 工件或 room-rxjava3 工件。如需了解详情,请参阅声明依赖项。

6.1 写异步单次查询

单次查询是指仅执行一次并在执行时获取数据快照的数据库操作。以下是异步单次查询的一些示例:

@Dao
public interface UserDao {@Insert(onConflict = OnConflictStrategy.REPLACE)public Completable insertUsers(List<User> users);@Updatepublic Completable updateUsers(List<User> users);@Deletepublic Completable deleteUsers(List<User> users);@Query("SELECT * FROM user WHERE id = :id")public Single<User> loadUserById(int id);@Query("SELECT * from user WHERE region IN (:regions)")public Single<List<User>> loadUsersByRegion(List<String> regions);
}

6.2 编写可观察查询

可观察查询是指在查询引用的任何表发生更改时发出新值的读取操作。

您可能需要用到可观察查询的一种情形是,帮助您在向底层数据库中插入项或者更新或移除其中的项时及时更新显示的列表项。下面是可观察查询的一些示例:

@Dao
public interface UserDao {@Query("SELECT * FROM user WHERE id = :id")public Flowable<User> loadUserById(int id);@Query("SELECT * from user WHERE region IN (:regions)")public Flowable<List<User>> loadUsersByRegion(List<String> regions);
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch基础: torch.unbind()

1. torch.unbind 作用 说明&#xff1a;移除指定维后&#xff0c;返回一个元组&#xff0c;包含了沿着指定维切片后的各个切片。 参数&#xff1a; tensor(Tensor) – 输入张量dim(int) – 删除的维度 2. 案例 案例1 x torch.rand(1,80,3,360,360)y x.unbind(dim2)print(&…

【进程等待】是什么 | 为什么 | 怎么办 | wait阻塞等待

目录 进程等待是什么&#xff1f; 为什么要进程等待&#xff1f; 如何进程等待&#xff1f; wait 阻塞等待 进程等待是什么&#xff1f; 进程终止会把进程退出的数据&#xff08;退出码和退出信号&#xff09;存放到进程的PCB中保存下来&#xff0c;让父进程进行等待。…

电脑提示‘找不到msvcr110dll,无法继续执行代码’的解决方法,3分钟快速修复

不知道大家有没有遇到过这种情况&#xff0c;无端端电脑提示你找不到msvcr110dll,无法继续执行代码&#xff1f;当出现这个情况&#xff0c;证明你的某个程序就已经运行不了&#xff0c;你需要去修复这个错误&#xff0c;才能正常的运行程序&#xff0c;下面我们一起来详细的了…

【算法】并查集

并查集是一种树形的数据结构&#xff0c;通常可以用于高效的合并多个集合和查询两个数是否属于同一个集合的情况。 其原理在于&#xff0c;把每个集合变成一棵树&#xff0c;树根的值就是整个集合的编号 其合并集合的效率远远高出普通的方式&#xff0c;近似O(1) 但是&#…

ChatGLM-Math:强化数学能力

大型语言模型&#xff08;LLM&#xff09;在文本摘要、问答和角色扮演对话等语言任务上表现出色&#xff0c;在数学推理等复杂问题上也具有应用潜力。 但目前提高 LLM 数学问题解决能力的方法&#xff0c;往往会导致其他方面能力的下降。例如RLHF的方法&#xff0c;虽然可以提…

YOLOv9全网最新改进系列:YOLOv9融合HCF-NET网络中的PPA模块,红外小目标实验证明针对小目标的改进具有出色表现!

YOLOv9全网最新改进系列&#xff1a;YOLOv9融合HCF-NET网络中的PPA模块&#xff0c;红外小目标实验证明针对小目标的改进具有出色表现&#xff01; YOLOv9原文链接戳这里&#xff0c;原文全文翻译请关注B站Ai学术叫叫首er B站全文戳这里&#xff01; 详细的改进教程以及源码…

牛客 二叉树 NB1 牛群的最大高度

原题链接 就不采用, 递归的方式来做了, 自己弄个栈来做 用栈来保存路径, curr 表示当前的节点, pre 保留往回走时的上一步 如果是 用递归来做 它的栈链路是这样的, 可以做下参考 黄色表示返回 用栈模拟的话, 不可能模拟得一摸一样, 递归的话一个栈会经过3次, 第三次后就不…

目录页码右对齐快速解决

选择目录–段落–制表符&#xff0c;按图中设置即可

C++类和对象(基础篇)

前言&#xff1a; 其实任何东西&#xff0c;只要你想学&#xff0c;没人能挡得住你&#xff0c;而且其实学的也很快。那么本篇开始学习类和对象&#xff08;C的&#xff0c;由于作者有Java基础&#xff0c;可能有些东西过得很快&#xff09;。 struct在C中的含义&#xff1a; …

ansible—playbook的template、tags、roles模块

目录 一、template 1、简介 2、template模块实例 1.先准备一个以.j2结尾的template模板文件&#xff0c;设置引用的变量&#xff0c;ansible上要先安装httpd 2、修改主机清单文件&#xff0c;使用主机变量定义一个变量名相同而值不同的变量 3、主机添加hosts 4、编写pla…

gitlab集群高可用架构拆分部署

目录 前言 负载均衡器准备 外部负载均衡器 内部负载均衡器 (可选)Consul服务 Postgresql拆分 1.准备postgresql集群 手动安装postgresql插件 2./etc/gitlab/gitlab.rb配置 3.生效配置文件 Redis拆分 1./etc/gitlab/gitlab.rb配置 2.生效配置文件 Gitaly拆分 1.…

python魔法方法是什么

魔法方法是python内置方法&#xff0c;不需要主动调用&#xff0c;存在的目的是为了给python的解释器进行调用&#xff0c;几乎每个魔法方法都有一个对应的内置函数&#xff0c;或者运算符&#xff0c;当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法&…