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();
}