目录
一、概述
1.1 描述
1.2 主要部件
二、创建 Room
2.1 添加依赖项
2.2 创建数据实体
2.2.1 设置 tableName or name 属性
2.2.2 设置主键
2.2.3 忽略字段
2.3 创建数据访问对象 (DAO)
2.4 创建数据库
三、使用 Room
3.1 创建数据库
3.2 添加数据
3.3 查找数据
3.4 修改数据
3.5 删除数据
四、相关链接
一、概述
1.1 描述
????????上文介绍到了SQLite Api,今天咱们介绍一下 Room ( Android Jetpack 重要成员之一 )。
????????Room 持久性库在 SQLite 之上提供了一个抽象层,以允许流畅的数据库访问,同时利用 SQLite 的全部功能。特别是,Room 提供以下好处:
????????由于这些考虑,我们强烈建议您使用 Room 而不是直接使用 SQLite API。
1.2 主要部件
Room 包含三个主要组件:
????????数据库类为您的应用程序提供与该数据库关联的 DAO 实例。反过来,应用程序可以使用 DAO 从数据库中检索数据作为关联数据实体对象的实例。该应用程序还可以使用定义的数据实体来更新相应表中的行,或创建新行以进行插入。下图说明了 Room 不同组件之间的关系。
二、创建 Room
2.1 添加依赖项
????????在 app/build.gradle文件中添加依赖:
dependencies?{
????//Room
????def?room_version?=?"2.4.1"
????implementation?"androidx.room:room-runtime:$room_version"
????annotationProcessor?"androidx.room:room-compiler:$room_version"
}
2.2 创建数据实体
????????将每个 Room 实体定义为一个使用 @Entity 注释的类。 Room 实体包括数据库中对应表中每一列的字段,包括一个或多个构成主键的列。因此,实体类往往是不包含任何逻辑的小型模型类。我们的 User 类代表数据库中数据的模型,告诉 Room 它应该基于这个类创建一个表:
@Entity
public?class?User?{
????@PrimaryKey
????public?int?id;
????
????public?String?mName;
????public?int?mAge;
}
????????通过将 @PrimaryKey 注释添加到正确的字段来设置主键(如:id)。
注意:要保留一个字段,Room 必须有权访问它。 你其设为 public 或为其提供 getter 和 setter 方法来确保 Room 可以访问该字段。
默认情况下:
2.2.1 设置 tableName or name 属性
@Entity(tableName?=?"users")
public?class?User?{
????@PrimaryKey
????public?int?id;
????@ColumnInfo(name?=?"name")
????public?String?mName;
????@ColumnInfo(name?=?"age")
????public?int?mAge;
}
????????此时我们将表名设置为 users 。将 mName 和 mAge 在表中的列名分别修改为 name 和 age。
注意:SQLite 中的表名和列名不区分大小写。
2.2.2 设置主键
1、定义单主键
????????每个 Room 实体必须定义一个主键,用于唯一标识相应数据库表中的每一行。最直接的方法是使用 @PrimaryKey 注释单个列,如上面 User 类中的 id 属性。
注意:如果你需要 Room 为实体实例分配自动 ID,请将 @PrimaryKey 的 autoGenerate 属性设置为 true
@Entity(tableName?=?"users")
public?class?User?{
????@PrimaryKey(autoGenerate?=?true)
????public?int?id;
}
2、定义复合主键
????????如果你需要通过多个列的组合来唯一标识实体的实例,你可以通过在 @Entity 的 primaryKeys 属性中列出这些列来定义复合主键:
@Entity(tableName?=?"users",primaryKeys?=?{"mName","mAge"})
public?class?User?{
????public?String?mName;
????public?int?mAge;
}
2.2.3 忽略字段
????????默认情况下,Room 为实体中定义的每个字段创建一个列。但是某些字段我们不需要保存到数据库,可以使用@Ignore 对其进行注释。
@Entity(tableName?=?"users")
public?class?User?{
????@Ignore??????//@Ignore?此属性不在数据库生产列
????public?String?nickname;
}
2.3 创建数据访问对象 (DAO)
????????DAO 负责定义访问数据库的方法。使用 Room,我们不需要所有与 Cursor 相关的代码,只需使用 UserDao 类中的注释定义我们的查询即可。每个 DAO 都包含提供对应用程序数据库的抽象访问的方法。在编译时,Room 会自动生成您定义的 DAO 的实现。
????????你可以将 DAO 定义为接口或抽象类。对于基本用例,通常应该使用接口。无论哪种情况,都必须使用 @Dao 注释你的 DAO。DAO 没有属性,但它们确实定义了一种或多种方法来与应用程序数据库中的数据进行交互。
@Dao?//这个是必须的
public?interface?UserDao?{
????//无需编写任何?SQL?代码即可在数据库中插入、更新和删除行的便捷方法。
????//新增单个实体
????@Insert
????void?insertUser(User?user);
????//新增多个实体
????@Insert
????void?insertUsers(List<User>?users);
????//更新数据
????@Update
????void?updateUser(User?user);
????//删除数据
????@Delete
????void?deleteUser(User?user);
????
????//编写自己的?SQL?查询(query)方法
????//查询?users?表
????@Query("SELECT?*?FROM?users")
????List<User>?getAll();
????//根据name查询?users?表,将参数集合传递给查询
????@Query("SELECT?*?FROM?users?WHERE?name?IN?(:usernames)")
????List<User>?loadAllByNames(int[]?usernames);
????//将简单参数传递给查询
????@Query("SELECT?*?FROM?users?WHERE?age?>?:minAge")
????public?User[]?loadAllUsersOlderThan(int?minAge);
}
2.4 创建数据库
????????定义一个 AppDatabase 类来保存数据库。AppDatabase 定义数据库配置并充当应用程序对持久数据的主要访问点。数据库类必须满足以下条件:
-
该类必须使用 @Database 注释进行注释,该注释包括一个实体数组,该数组列出了与数据库关联的所有数据实体。 -
该类必须是扩展 RoomDatabase 的抽象类。 -
对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数并返回 DAO 类实例的抽象方法。
import?androidx.room.Database;
@Database(entities?=?{User.class},version?=?1)
public?abstract?class?AppDatabase?{
????public?abstract?UserDao?userDao();
}
????????Room 的三个主要组件已经创建好了,咱们开始使用吧。
三、使用 Room
3.1 创建数据库
????????数据库保存路径:/data/data/com.scc.datastorage/files/room_db
注意:数据库的操作一定要放到子线程中,切不可在主线程中操作(否则会报错),虽然可以强制开启允许这么做,但不要在主线程中操作数据库,避免遇到ANR问题。
????????????//创建数据库
????????String?dir?=?getFilesDir()?+?"/room_db";
????????AppDatabase?db?=?Room.databaseBuilder(AppGlobalUtils.getApplication(),
????????????????AppDatabase.class,?dir)
????????????????.build();
允许在主线程中进行数据库操作:
????????在构建AppDatabase实例的时候,添加allowMainThreadQueries()方法,这样Room就可以在主线程中进行数据库操作了,但是这个方法只建议在测试环境下使用。
????????db?=?Room.databaseBuilder(AppGlobalUtils.getApplication(),
????????????????AppDatabase.class,?dir)
????????????????.allowMainThreadQueries()
????????????????.build();
3.2 添加数据
????????????List<User>?list?=?new?ArrayList<>();
????????????list.add(new?User(10,?"帅次次",?20,?"09:00"));
????????????list.add(new?User(12,?"朱元璋",?30,?"11:00"));
????????????list.add(new?User(15,?"赵匡胤",?40,?"13:00"));
????????????list.add(new?User(18,?"李世民",?50,?"15:00"));
????????????new?Thread(()?->?{
????????????????userDao.insertUsers(list);
????????????????Log.e("Room",?"插入成功:"?+?db.userDao().queryAll().size());
????????????}).start();
3.3 查找数据
????????????new?Thread(()?->?{
????????????????StringBuilder?sql?=?new?StringBuilder();
????????????????List<User>?list?=?userDao.queryAll();
????????????????sql.append(list.size());
????????????????if?(list.size()?>?0)?{
????????????????????for?(User?bean?:?list)?{
????????????????????????sql.append("\n").append(bean.toString());
????????????????????}
????????????????}
????????????????Log.e("Room",?sql.toString());
????????????}).start();
3.4 修改数据
????????????new?Thread(()?->?{
????????????????StringBuilder?sql?=?new?StringBuilder();
????????????????List<Integer>?id?=?new?ArrayList<>();
????????????????id.add(18);
????????????????List<User>?list?=?db.userDao().queryAllById(id);
????????????????if?(list.size()?>?0)?{
????????????????????sql.append("\n?修改数据前:").append(list.get(0).toString());
????????????????}
????????????????User?user?=?new?User(18,?"武媚娘",?32,?"12:00");
????????????????userDao.updateUser(user);
????????????????list?=?db.userDao().queryAllById(id);
????????????????if?(list.size()?>?0)?{
????????????????????sql.append("\n?修改数据后:").append(list.get(0).toString());
????????????????}
????????????????Log.e("Room",?String.valueOf(sql));
????????????}).start();
3.5 删除数据
????????????????new?Thread(()?->?{
????????????????????StringBuilder?sql?=?new?StringBuilder();
????????????????????List<User>?list?=?userDao.queryAll();
????????????????????if?(list.size()?>?0)?{
????????????????????????for?(User?bean?:?list)?{
????????????????????????????sql.append("\n").append(bean.toString());
????????????????????????}
????????????????????}
????????????????????User?user?=?new?User();
????????????????????user.id?=?12;
????????????????????db.userDao().deleteUser(user);
????????????????????sql.append("\n删除后");
????????????????????List<User>?listDelete?=?db.userDao().queryAll();
????????????????????Log.e(getClass().getName(),?"list:"?+?list.size());
????????????????????if?(listDelete.size()?>?0)?{
????????????????????????for?(User?bean?:?listDelete)?{
????????????????????????????sql.append("\n").append(bean.toString());
????????????????????????}
????????????????????}
????????????????????Log.e("Room",?sql.toString());
????????????????}).start());
????????然后你会发现 Room 和 SQLite的用法基本一致。操作简单易上手,说试试就试试。
四、相关链接
Android 数据全方案处理
|