本文记录几个使用 Room 的 Tips . 其他常规使用可参考 官方文档

Rxjava 结合使用订阅类选择

首先简单介绍下几个订阅类的特点

1. Completable

只有 onCompleteonError 方法 , 即是只有“完成”和“错误”两种状态 , 不会返回具体的结果

2. Single

其回调为 onSuccessonError , 查询成功会在onSuccess 中返回结果 , 需要注意的是 ,如果未查询到结果,即查询结果为空 , 会直接走 onError 回调 , 抛出EmptyResultSetException 异常

3. Maybe

其回调为 onSuccess , onError ,onComplete , 查询成功 , 如果有数据 ,会先回调onSuccess 再回调 onComplete , 如果没有数据 , 则会直接回调 onComplete

4. Flowable/Observable

这俩相信不用多介绍了,这是返回一个可观察的对象,每当查询语句查询的部分有变化时,都会回调它的 onNext 方法,直到Rx 流断开。

由于产品业务需求 , 对表的查询都是手动调用的 , 不需要保持 4 当中的观察状态 , 因此通常我们选用前三者 , 而 Completable 不会有返回结果 , 因此最终我们会在 2 3 中选择 .

应用中通常有列表查询业务 , 当数据为空时渲染数据为空 , 以往作者更习惯在 onNext 中进行处理 , 逻辑是结果也是成功的 , 只是数据为空 , 但 2和3 分别是不走成功回调 因此可能需要对其做一定封装 , 具体选择哪个看喜好而异.

最终代码结构 eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
AppDatabase.shared().userDao()
.selectPage(page,pageSize)
.compose(ScheduleCompat.applyMayBe())
.subscribe(new RHObserver<Page<User>>() {
@Override
protected void success(Page<User> data) {
// handle data
}

@Override
protected void failure(MyError error) {
// handle error
}
});

其他关于 Rxjava 与 Room 结合使用的可参考 文章

模糊查询

1
2
//查询表user中的user_name 包含‘黄’字的user集合
select * from user where user_name like '%黄%'

Room中用||代替+号

1
2
3
4
5
6
// ||相当于+
@Transaction
@Query("SELECT * FROM user WHERE user_name LIKE '%' || :searchName || '%' ")
fun queryUser(searchName: String): List<User>


Room 警告

问题: 在使用Room架构组建中,AS 警告: Primary key constraint on grade is ignored when being merged into *

原因:使用了 @Embedded 注解

解决:在该处添加注解 @SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)

1
2
3
4
5
6
7
8
@Entity(tableName = "test") // 如果数据库表的名不指定,即 @Entity,默认同类名
public class User {
@PrimaryKey(autoGenerate = true)
public int id;

@ColumnInfo(name = "name") // 如果字段名和数据库表的列名相同,可以省略该注解
public String name;
}
1
2
3
4
5
6
7
8
9
@Entity
public class City {
@PrimaryKey
public int id;

@SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED) // 如果没有该注解,Android Studio编译的时候会报警告,但不影响编译运行。
@Embedded // 该注解会在数据库表City生成的时候加入User类中各字段对应的列,其中User类里声明的主键在City表中只是作为普通列。
public User mayor;
}

条件查询

多条件筛选查询时 , 根据条件返回全部或筛选后的数据

1
2
3
4

@Query("SELECT * FROM PeopleBean WHERE :name='' or name= :name")
Single<List<PeopleBean>> getAllTest(String name);

多参数

这里再增加一个sex字段。-1就查全部。

1
2
3
@Query("SELECT * FROM PeopleBean WHERE (:name='' or name=:name) and (:sex =-1 or sex=:sex)")
Single<List<PeopleBean>> getAll(String name, int sex);

参考链接: 掘金

增加唯一索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity(indices = {@Index(value = {"first_name", "last_name"},
unique = true)})
public class User {
@PrimaryKey
public int id;

@ColumnInfo(name = "first_name")
public String firstName;

@ColumnInfo(name = "last_name")
public String lastName;

@Ignore
Bitmap picture;
}

相同字段处理

若某个复合类包含多个形同嵌套字段 , 可通过设置 prefix 来确保每个列的唯一性 , 但是在自定义 sql 时需要对添加了 prefix 属性的字段进行手动添加

1
2
3
4
5
6
7
8
9
10
11
12
public class TrainPatientWithGame {

@Embedded
public TrainWithGame trainWithGame;

@Embedded(prefix = "p_")
public Patient patient;

public Integer totalTrainCount;


}

由于 trainWithGamepatient 都有 patientId 这个属性 , 因此在外层复合类给 patient 增加一个 prefix 属性 ,在对应自定义 SQL 时 需要手动添加相关属性

1
2
3
@Transaction
@Query("SELECT T.*,P.patient_id AS p_patient_id ... )
abstract List<TrainPatientWithGame> selectCombine()