RxJava2 Single.Concat 用于存储库模式
RxJava2 Single.Concat for repository pattern
我使用带有 RxJava2 的 Room 来通过存储库模式原则实现我的数据层。
我有以下简单的代码来决定从哪里获取数据。
@Override
public Single<Team> getTeamById(int teamId) {
return Single.
concat(local.getTeamById(teamId),
remote.getTeamById(teamId)).
filter(team -> team != null).
firstOrError();
}
这里的问题是,如果数据不可用,它 returns 来自第一个源(本地)的错误,而不是转到远程源。
android.arch.persistence.room.EmptyResultSetException: Query returned empty result set: select * from teams where id = ?
我应该如何指示 concat 放弃接收到的任何错误并继续其串联?
只要您不确定是否可以从您的数据提供商那里接收至少一个团队,您应该考虑使用 Maybe 而不是 Single。
您可以在此处查找定义:
Single 正如它所说:
it always either emits one value or an error notification
改用 Maybe:
Maybe
there could be 0 or 1 item or an error signalled by some reactive
source
正如您的错误所述,从您的查询中提取结果时似乎出现了问题。
正确处理结果提取,以便在尝试提取任何结果之前检查是否有结果。因此,Maybe 会 return 0 或 1 个项目,并且在找不到团队时根本不会抛出任何错误。
你不能在 RxJava2 中传递 null。因此,只要您的本地存储库为空,您就不能 return null 在您的单曲中。有一个关于处理空对象的堆栈问题:
您还可以在这里找到一篇文章,向您展示了使用 RxJava2 的存储库模式的首选实现:
https://android.jlelse.eu/rxjava-2-single-concat-sample-for-repository-pattern-1873c456227a
如此简化 - 而不是从本地和远程回购中 returning null 传递某种 "empty" 对象。这在您的业务逻辑中也很有用,允许您识别空数据集。
如果您想在第一个源错误时继续(而不是完成为空),您可以使用 onErrorResumeNext
而不是 concat
(我假设两个 get 调用 return Observable
, 根据需要调整):
return local.getTeamById(teamId)
.onErrorResumeNext(error -> {
if (error instanceof EmptyResultSetException) {
return remote.getTeamById(teamId));
}
return Observable.error(error);
})
.firstOrError();
我使用 Maybe
解决了我的 Rxjava2
存储库模式问题。
对于你的情况,我会用下面的代码来解决:
//you may need to rewrite your local.getTeamById method
protected Maybe<Team> getTeamById(int teamId) {
Team team = localDataHelper.getTeamById(teamId);
return team != null ? Maybe.just(team) : Maybe.empty();
}
@Override
public Single<Team> getTeamById(int teamId) {
Maybe<Team> cacheObservable = local.getTeamById(teamId);
Maybe<Team> apiCallObservable = remote.getTeamById(teamId).toMaybe();
return Maybe.concat(cacheObservable, apiCallObservable)
.toSingle();
}
我使用带有 RxJava2 的 Room 来通过存储库模式原则实现我的数据层。
我有以下简单的代码来决定从哪里获取数据。
@Override
public Single<Team> getTeamById(int teamId) {
return Single.
concat(local.getTeamById(teamId),
remote.getTeamById(teamId)).
filter(team -> team != null).
firstOrError();
}
这里的问题是,如果数据不可用,它 returns 来自第一个源(本地)的错误,而不是转到远程源。
android.arch.persistence.room.EmptyResultSetException: Query returned empty result set: select * from teams where id = ?
我应该如何指示 concat 放弃接收到的任何错误并继续其串联?
只要您不确定是否可以从您的数据提供商那里接收至少一个团队,您应该考虑使用 Maybe 而不是 Single。
您可以在此处查找定义:
Single 正如它所说:
it always either emits one value or an error notification
改用 Maybe: Maybe
there could be 0 or 1 item or an error signalled by some reactive source
正如您的错误所述,从您的查询中提取结果时似乎出现了问题。
正确处理结果提取,以便在尝试提取任何结果之前检查是否有结果。因此,Maybe 会 return 0 或 1 个项目,并且在找不到团队时根本不会抛出任何错误。
你不能在 RxJava2 中传递 null。因此,只要您的本地存储库为空,您就不能 return null 在您的单曲中。有一个关于处理空对象的堆栈问题:
您还可以在这里找到一篇文章,向您展示了使用 RxJava2 的存储库模式的首选实现: https://android.jlelse.eu/rxjava-2-single-concat-sample-for-repository-pattern-1873c456227a
如此简化 - 而不是从本地和远程回购中 returning null 传递某种 "empty" 对象。这在您的业务逻辑中也很有用,允许您识别空数据集。
如果您想在第一个源错误时继续(而不是完成为空),您可以使用 onErrorResumeNext
而不是 concat
(我假设两个 get 调用 return Observable
, 根据需要调整):
return local.getTeamById(teamId)
.onErrorResumeNext(error -> {
if (error instanceof EmptyResultSetException) {
return remote.getTeamById(teamId));
}
return Observable.error(error);
})
.firstOrError();
我使用 Maybe
解决了我的 Rxjava2
存储库模式问题。
对于你的情况,我会用下面的代码来解决:
//you may need to rewrite your local.getTeamById method
protected Maybe<Team> getTeamById(int teamId) {
Team team = localDataHelper.getTeamById(teamId);
return team != null ? Maybe.just(team) : Maybe.empty();
}
@Override
public Single<Team> getTeamById(int teamId) {
Maybe<Team> cacheObservable = local.getTeamById(teamId);
Maybe<Team> apiCallObservable = remote.getTeamById(teamId).toMaybe();
return Maybe.concat(cacheObservable, apiCallObservable)
.toSingle();
}