如何捕获失败的呼叫并继续其余的网络呼叫?

2022-04-10 00:00:00 android java rx-java2 rx-java

我正在进行5个并行网络调用,模拟其中4个成功,1个失败。

失败的调用会导致整个Single.zip()失败,并且我无法获取其他4个网络调用的结果,即使它们已经成功。

如何处理Single.zip()中单个网络调用失败的错误,并获取成功的网络调用的结果?

private Single<BigInteger> createNetworkCall(){
        return Single.fromCallable(() -> {
            
            return service.getBalance("validaddress").execute();
        }).subscribeOn(Schedulers.io());
}
private Single<BigInteger> createFailedNetworkCall(){
        return Single.fromCallable(() -> {
            
            return service.getBalance("invalidaddress").execute();
        }).subscribeOn(Schedulers.io());
}
private void makeParallelCalls(){
        List<Single<BigInteger>> iterable = new ArrayList<>();
        iterable.add(createNetworkCall());
        iterable.add(createNetworkCall());
        iterable.add(createNetworkCall());
        iterable.add(createNetworkCall());
        iterable.add(createFailedNetworkCall());

        Single.zip(iterable, (results) -> {
            Log.d(TAG, "makeParallelCalls: " + Arrays.toString(results));
            return results;
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(results-> {
                    Log.d(TAG, "onSuccess: makeParallelCalls: " + results);

                }, (exception) -> {
                    Log.e(TAG, "onError: makeParallelCalls", exception);

                });
}

解决方案

捕获异常,不允许该错误中断Single.Zip。

例如,在您的请求工厂中,返回可选而不是响应。

private Single<Optional<Long>> performNetworkCall(int n){
    return Single.fromCallable(() -> {
        if (n % 2 == 0) {
            throw new Exception("failed call");
        }
        return 0L;
    }).subscribeOn(Schedulers.io())
    .map(Optional::of)
    .onErrorReturnItem(Optional.empty());
    // or .onErrorReturn(exception -> Optional.empty());
}

private void makeParallelCalls(){
    List<Single<BigInteger>> iterable = new ArrayList<>();
    iterable.add(performNetworkCall(1));
    iterable.add(performNetworkCall(2));
    iterable.add(performNetworkCall(3));
    iterable.add(performNetworkCall(4));
    iterable.add(performNetworkCall(5));

    Single.zip(iterable, (results) -> {
                for (Object result : results) {
                    var optional = (Optional<Integer>)result;
                    if (optional.isEmpty()) {
                        // this one failed, no data
                    } else {
                        var response = optional.get();
                    }
                }
                return results;
            });
}

您可以将可选替换为包含附加信息的自定义类,例如导致失败的异常或错误信息。

如果您有恢复选项,则可以改用.onErrorResumeNext

相关文章