RxJava(五)zipWith操作符
本篇文章来给大家简单介绍一下zipWith的用法,这里先将用到的方法贴出:
String BASE_URL = "http://192.168.1.182:8089";
@GET("/app/check/charge")
Observable<ChargeModel> getCharge();
@GET("/app/check/state")
Observable<StateModel> getState();
记得在拥抱RxJava(一)基本用法中提到过这样一个需求,先去查询对方的在线状态,查询成功之后再去查询用户余额,如果用户有余额就去拨打电话,当时的做法是这样的:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getState()
.flatMap(new Func1<StateModel, Observable<ChargeModel>>() {
@Override
public Observable<ChargeModel> call(StateModel stateModel) {
return stateModel.getState() != 0 ? Observable.empty() : apiManger.getCharge();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ChargeNodel>() {
@Override
public void onCompleted() {
//hideLoading();
}
@Override
public void onError(Throwable e) {
//hideLoading();
}
@Override
public void onNext(ChargeModel chargeModel) {
if(chargeModel.getCharge() > 0){
//拨打电话
}
}
});
我们先去查询用户状态,查询成功后使用flatMap操作符再发射一个检查余额的流,此时的对象已经转换为余额对象,最后如果余额大于0就拨打电话,这种方法其实是一步一步来执行的。
仔细想一下,其实能够拨打电话的情况只有一种,那就是对方在线并且用户余额大于0,那如果使用今天的主角zipWith该怎么实现呢?废话不多说,直接上代码:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getState()
.zipWith(apiManger.getCharge(), new Func2<StateModel, ChargeModel, Boolean>() {
@Override
public Boolean call(StateModel stateModel, ChargeModel chargeModel) {
return stateModel.getState() == 0 && chargeModel.getCharge() > 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Boolean canCall) {
if (canCall) {
//拨打电话
}
}
});
我们先调用getState方法,接着使用zipWith操作符,第一个参数是另外一个被观察者,第二个参数是Fun2,可以看到在实例化Fun2后,被请求下来的状态和余额都已经传递过来了,我们知道flatMap转换的是对象,而现在这两个需要的对象已经拿到了,就没必要转换对象呢,我们完全可以根据stateModel.getState() == 0 && chargeModel.getCharge() > 0这个条件返回一个boolean值,然后在onNext中判断是否满足打电话的条件执行操作。其实想想使用zipWith更加合理,因为在线状态和余额都是必要条件,所以完全可以放在一起去请求,这两个数据流中有一个发生错误就会终止,这和第一种方法不满足条件时返回Observable.empty()的结果是一样的。最后简化的代码是这个样子:
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getState()
.zipWith(apiManger.getCharge(), (stateModel, chargeModel) -> stateModel.getState() == 0 && chargeModel.getCharge() > 0)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(canCall -> {
if (canCall) {
//拨打电话
}
}, throwable -> Logger.e(throwable.toString()));
怎么样,如果用了RxJava是不是很爽?!
现在又有另外一个需求,假设我们需要使用余额购买一件商品,当余额不够购买商品时提示用户余额不足,使用zipWith该怎么办呢?
ApiManger apiManger = RetrofitHelper.getManger();
apiManger.getMoney()
.zipWith(apiManger.getCharge(), new Func2<MoneyModel, ChargeModel, Boolean>() {
@Override
public Boolean call(MoneyModel moneyModel, ChargeModel chargeModel) {
return moneyModel.getMoney() > chargeModel.getCharge();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean) {
ToastUtil.show(getApplicationContext(), "余额不足");
}
}
});
同时获取价格(原谅我把charge这个单词用给了余额)和余额后比较大小,判断是否提示。现在请大家想一下如果是第一种方法使用flatMap能不能实现这种功能呢?我认为是不太容易实现的,因为这种需求是同时需要两个对象的,而flatMap最后转换的结果只能生成一个对象在onNext是无法比较的,所以flatMap更适合按顺序一步步执行的情况。