链接两个Observable返回另一个

时间:2014-08-27 06:05:43

标签: java reactive-programming retrofit rx-java

我有两个名为A<'ModelA'>的观察者。和B<'ModelB'>。它们中的每一个都对不同的REST服务执行请求,因此它们扩展了如上所述的不同模型。任何人执行的请求都可能失败。现在,我需要能够链接它们并返回一个ModelC对象。所以,伪编码流将是这样的:

A< 'MODELA' >执行请求,如果失败则执行某些操作,如果没有则将其结果(responseModelA)传递给B<'ModelB'>所以它可以执行另一个REST请求,涉及使用responseModelA的一部分。如果B失败会发生某种情况,如果没有,则将其响应(responseModelB)与responseModelA(手动设置POJO字段)组合在一起以创建ModelC,这是订户应该在其 call()方法。

使用rxJava可以远程编码吗?我非常坚持这一点,所以我对任何消息都持开放态度。

感谢。

2 个答案:

答案 0 :(得分:5)

这假设您已创建一个REST请求接口,该接口返回类似于以下内容的Observable(使用Retrofit这非常简单):

interface RestApi {
    Observable<ModelA> getModelA();
    Observable<ModelB> getModelB(int modelBId);
}

class ModelA {
    int modelBId;
    Object fieldA;
}

class ModelB {
    Object fieldB;
}

class ModelC {
    Object fieldFromA;
    Object fieldFromB;

    public ModelC(Object fieldFromA, Object fieldFromB) {
        this.fieldFromA = fieldFromA;
        this.fieldFromB = fieldFromB;
    }
}

要使ModelB请求依赖于ModelA请求的结果,可以使用.flatMap将一个Observable的结果转换为另一个Observable。

然后,要创建ModelC,请使用.map从ModelA和ModelB中选择所需的字段并返回结果。

RestApi restApi;

Observable<ModelC> observeModelC() {
    return restApi
            .getModelA()
            .flatMap(new Func1<ModelA, Observable<ModelC>>() {
                @Override
                public Observable<ModelC> call(final ModelA modelA) {
                    // Use the modelBId from modelA to get ModelB.
                    return restApi
                            .getModelB(modelA.modelBId)
                            // Combine A & B to create C
                            .map(new Func1<ModelB, ModelC>() {
                                @Override
                                public ModelC call(ModelB modelB) {
                                    return new ModelC(modelA.fieldA, modelB.fieldB);
                                }
                            });
                }
            });
}

您的订阅者将如下所示:

observeModelC()
        .subscribe(new Observer<ModelC>() {
            @Override
            public void onCompleted() {
                // All done.
            }

            @Override
            public void onError(Throwable e) {
                // All errors from any API request will end up here.
                // For Retrofit, cast e to RetrofitError for
                // detailed error info.
            }

            @Override
            public void onNext(ModelC modelC) {
                // Yeah! - Use modelC.
            }
        });

答案 1 :(得分:1)

顺序组合在Rx.NET中由SelectMany实现(我认为它在Rx.Java中是FlatMap)。 Rx.NET也适用于快速失败的语义,因此SelectMany可能就是您所需要的。

(C#)

IObservable<ModelC> query = A().FlatMap(B, (a, b) => C(a, b));

query.Subscribe(success => DoSomethingSuccessful(), error => DoSomethingElse(error));

其中AB是返回observables的函数,C是返回ModelC的函数。

但是,如果您想在A或B失败时执行某些特定操作,那么Rx.NET中的快速解决方案是使用Do运算符。

IObservable<ModelC> query = A().Do(_ => {}, AFailed)
                               .FlatMap(B.Do(_ => {}, BFailed), (a, b) => C(a, b));

query.Subscribe(success => DoSomethingSuccessful(), UltimateFailure);

其中AFailedBFailed是返回void的方法,接受单个Exception参数。

抱歉,我不了解Java,但也许这会引导您找到正确的解决方案。