仅在条件匹配时才返回组合的Observable

时间:2016-12-19 08:11:14

标签: android operators rx-java

考虑以下集合和对象:

Observable.from(users); // Where users = List<User> and each user has a userId
Observable.just(location); // Where location has id, userId, coordinates

我想要做的是迭代用户列表,并在第一次遇到数据库中查询location.userId.equals(user.userId);时,返回一个组合对象。如果userId s不匹配,请移至下一位用户。并在找到1匹配后终止循环。

如何使用RxJava实现此目的?

我最初想过要用:

Observable.zip(Observable.from(users), Observable.just(location), new Func2<User, Location, UserLocation>() { ... });`

有没有人有更好的选择?

编辑:

我想也许我可以用一个简单的解决方案解决这个问题,但好吧我会更清楚地解释一切。

所以,一旦我有location.userIduser.userId,我还需要查询一个数据库,该数据库将返回Observable<Boolean>,表明它在我们的数据库中是否也是真的。如果该条件匹配,那么我返回一个组合对象。

所以整个流程看起来像这样:

for each user in Users {
    checkIfAlreadyExistsInDatabase(user.userId, location.userId) // Returns Observable<Boolean>

    // If exists in db AND user.userId == location.userId return combined object and terminate the loop
}

以前是在没有RxJava的情况下同步完成的。我将方法checkIfAlreadyExistsInDatabase转换为Rx并使用Schedulers.io在后​​台线程上ping数据库以使应用程序更具响应性。当我不得不迭代一组用户并将id与Location AND匹配并且ping我的数据库时,问题出现了。

为了让我调用方法checkIfAlreadyExistsInDatabase,我需要抓取user.userId并执行此操作,我需要迭代users并使用location.userId进行过滤。< / p>

所以:

  1. 迭代用户
  2. 如果user.userId与location.userId匹配,请检查它是否存在于数据库中
  3. 如果存在于数据库中,则返回组合对象
  4. 找到1匹配后终止循环

3 个答案:

答案 0 :(得分:2)

zip函数的问题在于它从左Observable发出一个项目,从右Observable发出一个项目。因此,您提供的功能仅对第一个用户执行。但这是一个很好的方向。只需重复第二次Observable适当的次数 - 使用repeat。如果你真的想使用RxJava这样做,这是建议的方法:

Observable.zip(Observable.from(userList),
        Observable.just(location).repeat(userList.size()),
        new Func2<User, Location, User>() {
            @Override
            public User call(User user, Location location) {
                return user.id.equals(location.id) ? user : null;
            }
        })
        .filter(new Func1<User, Boolean>() {
            @Override
            public Boolean call(User user) {
                return user != null;
            }
        });

但是,使用此方法null会通过Observable流传递,但不建议这样做。

我不会使用RxJava,只使用传统的Java Iterator

答案 1 :(得分:2)

这不只是Observable.just(location),对吗?如果它已经知道,那么它是微不足道的。假设它也是异步获得的,那么flatMap的2参数形式就是你的朋友:

Observable
.just(location)
.flatMap(loc -> Observable
    .from(users)
    .filter(user -> user.userId == location.userId)
    .flatMap(user -> checkIfAlreadyExistsInDatabase(user.userId, loc.userId)
                     .filter(value->value),
             (user, value) -> user)
    .take(1)
    .map(user -> combine(user, location)
)
.subscribe(...);

答案 2 :(得分:1)

好的,这似乎是一个很好的方法(没有经过测试的思考,所以要小心):

Observable<UserLocation> getUserLocationObservable() {

    location = getLocation();
    return Observable.from(users)
        .flatMap(user -> return mPresenterRx.userIdAlreadyInDatabase(location, user.userId)
            .flatMap(alreadyExists -> alreadyExists ? Observable.just(user) : null))
        .filter(user -> return user != null)
        .take(1)
        .map(user -> return combine(location, user)); // Returns a UserLocation
}

// Combine 
Observable<UserLocation> userLocationObs = getUserLocationObservable();
Observable<OtherModel> otherModelObs = getOtherModelObs();
Observable.zip(userLocationObs, otherModelObs, ...)
    .subscribe(...);

很可能如果你想继续对此进行操作,你可以在这个和另一个可观察对象上压缩或组合:

{{1}}

如果有人在此处发现问题,请在下方发表评论。