考虑以下集合和对象:
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.userId
和user.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>
所以:
答案 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}}
如果有人在此处发现问题,请在下方发表评论。