如何在链接observable时传递变量?

时间:2016-01-18 19:12:24

标签: reactive-programming rx-java

我对RxJava很陌生,每当我遇到需要从链中的一个observable传递返回数据直到调用'订阅' - 我无法理解如何做到这一点“反应性”。没有任何补丁的方式...

例如:

Observable<GameObject> obs1 = func1();
Observable<GameObject> obs2 = func2();
Observable<GameObject> obs3 = func3();
Observable<GameObject> obs3 = func4();

我想发出obs1和obs2,得到他们的结果,然后发出obs3然后发出obs4然后用subscribe结束链,同时可以访问obs1,obs2,obs3和obs4的结果。

调用的顺序很重要,我需要在执行obs3之前完成obs1和obs2。

同样适用于obs3和obs4 - 在执行obs4之前我需要完成obs3才能完成。

我该怎么做?

我知道这是一个非常消解的问题 - 但这是开发人员开始了解rxJava时最棘手的问题之一。

感谢。

2 个答案:

答案 0 :(得分:3)

您可以使用Observable.zip和简单Observable.map / Observable.flatMap执行此操作:

Observable.zip(obs1, obs2, (res1, res2) -> {
    // do stuff with res1, res2
    return obs3.flatMap(res3 -> {
        // do stuff with res1, res2, res3
        return obs4.flatMap(res4 -> {
            // do stuff with res1, res2, res3, res4
            return result;
        });
    });
});

这会强制您的日程安排要求:

  • observables 1 and 2

  • observable 3

  • observable 4

答案 1 :(得分:0)

由于我前段时间有同样的怀疑,所以问题与Observables的实际工作方式有关。

假设您使用以下内容创建了obs1和obs2: Observable<GameObject> obs1 = Observable.create(...) Observable<GameObject> obs2 = Observable.create(...)

您有2个独立且断开连接的流。当他们每个人都应该做一些像网络请求或一些密集的后台处理时,这就是你想要的,这可能需要一些时间。

现在,让我们假设您想要观察两个结果并在它们准备好后从它们中发出一个值(您没有明确说明,但它会帮助您了解它是如何工作的)。在这种情况下,您可以使用zipWith运算符,它接受一对项目,第一个Observable中的第一个项目和第二个Observable中的第二个项目,将它们组合成一个项目,并将其发送到可能对它感兴趣的链中的下一个。从一个Observable调用zipWith,并期望另一个Observable作为param被压缩。它还需要一个自定义函数,它知道如何压缩2个源项并从中创建一个新项。

Observable<CustomObject> obs3 = obs1.zipWith(obs2, new Func2<GameObject, GameObject, CustomObject>() {
    @Override 
    public CustomObject call(GameObject firstItem, GameObject secondItem) {
        return new CustomObject(firstItem, secondItem);
    }
});

在这种情况下,CustomObject只是一个pojo。但它可能是另一个长期运行的任务,或者你需要处理前两个Observable项目的结果。

如果你想等待(或观察!)来自obs3的结果,你可以在最后插入另一个Observable,它应该执行另一个处理。

Observable<FinalResult> obs4 = obs3.map(new Func1<CustomObject, FinalResult>() {
    @Override
    public FinalResult call(CustomObject customObject) {
         return new FinalResult(customObject);
    }
});

map运算符将一个对象转换(或映射)到另一个对象。因此,您可以执行另一个处理或任何数据操作,并从中返回结果。或者您的FinalResult可能是常规课程,例如CustomObject,只是持有对其他GameObject的引用...您可以将其命名。

根据您创建Observable的方式,他们可能还没有开始发射任何物品。到目前为止,您只是创建和插入数据管道。为了触发第一个任务并使项目在流中流动,您需要订阅它。

obs4.subscribe();

总结一下,你并没有真正拥有一个传递整个链条的变量。实际上,您在第一个Observable中创建了一个项目,该项目在准备就绪时会通知第二个项目,依此类推。另外,每个步骤(可观察的)以某种方式转换数据。所以,你有一系列转型。

RxJava遵循功能方法,将高阶函数(map,zip,filter,reduce)应用于您的数据。明确这一点至关重要。此外,数据始终是不可变的:您不会真正更改Observable,也不会更改您自己的对象。它创建了它们的新实例,旧对象最终将被垃圾收集。因此obs1.zip(...)不会更改obs1,它会创建一个新的Observable实例,您可以将其分配给变量。

您也可以删除变量赋值(obs1,obs2,obs3等)并将所有方法链接在一起。一切都是强类型的,所以编译器不会让你插入彼此不匹配的Observable(一个的输出应匹配下一个的输入)。

我希望它会给你一些想法!