等待多个observable完成返回不同数量的元素

时间:2016-10-22 06:05:20

标签: java rx-java reactivex

场景:我有一个customerID字符串,用于查询多个不同的后端系统:日历,帮助台,ERP,CRM等。我想编译单个报告。 所以我粗略地(psydocode):

Result myResult = new Result();
Observable<Cal> cal = Calbackend.get(customerid);
cal.subscribe(calentry -> myResult.addCal(calentry));

Observable<Erp> erp = ERPbackend.get(customerid);
erp.subscribe(erpentry -> myResult.addErp(erpentry));

Observable<Help> help = Helpbackend.get(customerid);
help.subscribe(helpentry -> myResult.addHelp(helpentry));

Observable<Crm> crm = CRMbackend.get(customerid);
crm.subscribe(crmentry -> myResult.addCrm(crmentry));

// Magic here?

return result;

我想到的方法:使用defer()来阻止开始,然后另外为每个订阅count()。然后我可以对计数元素进行压缩,因为它们每个只发出一个项目(而其他项目将有不同数量的事件)。但是,如果myResult.add执行速度低于count(),则可能会导致数据丢失。

我想到的另一个选项是为每个订阅设置一个布尔标志数组,并检查每个完成(和错误)事件(如果所有这些都已完成)并对其执行回调或使用阻塞。 / p>

我看了herehere,但这些示例涉及常数或数据类型。

或者有更好/推荐的方式吗?

1 个答案:

答案 0 :(得分:1)

运营商toList可以与zip一起使用,如下所示:

Observable<List<Cal>> cal = Calbackend.get(customerid).toList();
Observable<List<Erp>> erp = ERPbackend.get(customerid).toList();
Observable<List<Help>> help = Helpbackend.get(customerid).toList();
Observable<List<Crm>> crm = CRMbackend.get(customerid).toList();
Observable.zip(cal, erp, help, crm,
                new Func4<List<Cal>, List<Erp>, List<Help>, List<Crm>, Result>() {
                    @Override
                    public Result call(List<Cal> cals, List<Erp> erps, List<Help> helps, List<Crm> crms) {
                        Result myResult = new Result();
                        // add all cals, erps, helps and crms to result
                        return myResult;
                    }
                })
                .subscribe(new Subscriber<Result>() {
                    @Override
                    public void onNext(Result result) {
                        // do something with the result
                    }

                    ...
                });

说明:顾名思义,toList运算符创建源observable发出的项的列表(当源可观察完成时,列表只发出一次)然后使用zip来组合可观察量的结果。

编辑:如果这些Observable可能会发出错误,您可以使用onErrorReturn来保持正常流程:

Observable<List<Cal>> cal = Calbackend.get(customerid)
            .onErrorReturn(new Func1<Throwable, Cal>() {
                @Override
                public Cal call(Throwable throwable) {
                    // Return something in the error case
                    return null;
                }
            })
            .toList();