我正在学习RxJava,作为我的第一个实验,试图在this code中的第一个run()
方法中重写代码(引用Netflix's blog作为RxJava可以帮助解决的问题)使用RxJava改进其异步性,即在继续执行其余代码之前不等待第一个Future(f1.get()
)的结果。
f3
取决于f1
。我知道如何处理这个问题,flatMap
似乎可以解决这个问题:
Observable<String> f3Observable = Observable.from(executor.submit(new CallToRemoteServiceA()))
.flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String s) {
return Observable.from(executor.submit(new CallToRemoteServiceC(s)));
}
});
接下来,f4
和f5
取决于f2
。我有这个:
final Observable<Integer> f4And5Observable = Observable.from(executor.submit(new CallToRemoteServiceB()))
.flatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer i) {
Observable<Integer> f4Observable = Observable.from(executor.submit(new CallToRemoteServiceD(i)));
Observable<Integer> f5Observable = Observable.from(executor.submit(new CallToRemoteServiceE(i)));
return Observable.merge(f4Observable, f5Observable);
}
});
哪个开始变得怪异(merge
他们可能不是我想要的......)但是允许我最后这样做,而不是我想要的:
f3Observable.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("Observed from f3: " + s);
f4And5Observable.subscribe(new Action1<Integer>() {
@Override
public void call(Integer i) {
System.out.println("Observed from f4 and f5: " + i);
}
});
}
});
这让我:
Observed from f3: responseB_responseA
Observed from f4 and f5: 140
Observed from f4 and f5: 5100
这是所有数字,但不幸的是我在单独的调用中得到结果,所以我无法完全替换原始代码中的最终println:
System.out.println(f3.get() + " => " + (f4.get() * f5.get()));
我不明白如何在同一行上访问这两个返回值。我想可能有一些功能性编程我在这里缺少。我怎样才能做到这一点?感谢。
答案 0 :(得分:18)
看起来你真正需要的是对如何使用RX的更多鼓励和观点。我建议你阅读更多文档和大理石图表(我知道它们并不总是有用)。我还建议调查lift()
函数和运算符。
map
,flatMap
和filter
的操作是操纵数据流中的数据运算符的要点是允许您中断稳定的可观察流并在数据流上定义自己的操作。例如,我编码了一个移动平均算子。这总结了一个Observable of double中的n
double
来返回移动平均线流。代码字面上看起来像这样
Observable movingAverage = Observable.from(mDoublesArray).lift(new MovingAverageOperator(frameSize))
您可以放心,您认为理所当然的许多过滤方法都有lift()
。
随着说;合并多个依赖项所需的只有:
map
或flatMap
答案 1 :(得分:7)
编辑:有人将以下文字转换为答案,我将此问题作为编辑添加到答案中,我很欣赏,并且理解可能是正确的SO事情,但是<我不认为这是一个答案,因为它显然不是正确的方法。我不会使用此代码,也不会建议任何人复制它。 欢迎其他/更好的解决方案和评论!
我能够通过以下方式解决这个问题。我没有意识到你可以flatMap
多次观察到一次,我认为结果只能消耗一次。所以我只是flatMap
f2Observable两次(抱歉,我在我的原始帖子中重命名了代码中的一些内容),然后在所有Observable上重命名zip
,然后订阅它。由于类型杂乱,Map
中zip
聚合值是不合需要的。 欢迎其他/更好的解决方案和评论! full code is viewable in a gist。谢谢。
Future<Integer> f2 = executor.submit(new CallToRemoteServiceB());
Observable<Integer> f2Observable = Observable.from(f2);
Observable<Integer> f4Observable = f2Observable
.flatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer integer) {
System.out.println("Observed from f2: " + integer);
Future<Integer> f4 = executor.submit(new CallToRemoteServiceD(integer));
return Observable.from(f4);
}
});
Observable<Integer> f5Observable = f2Observable
.flatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer integer) {
System.out.println("Observed from f2: " + integer);
Future<Integer> f5 = executor.submit(new CallToRemoteServiceE(integer));
return Observable.from(f5);
}
});
Observable.zip(f3Observable, f4Observable, f5Observable, new Func3<String, Integer, Integer, Map<String, String>>() {
@Override
public Map<String, String> call(String s, Integer integer, Integer integer2) {
Map<String, String> map = new HashMap<String, String>();
map.put("f3", s);
map.put("f4", String.valueOf(integer));
map.put("f5", String.valueOf(integer2));
return map;
}
}).subscribe(new Action1<Map<String, String>>() {
@Override
public void call(Map<String, String> map) {
System.out.println(map.get("f3") + " => " + (Integer.valueOf(map.get("f4")) * Integer.valueOf(map.get("f5"))));
}
});
这就产生了我想要的输出:
responseB_responseA => 714000
答案 2 :(得分:2)
我认为你要找的是switchmap。我们遇到了类似的问题,我们有一个会话服务来处理从api获取新会话,我们需要该会话才能获得更多数据。我们可以添加会话observable,它返回sessionToken,以便在我们的数据调用中使用。
getSession返回一个observable;
public getSession(): Observable<any>{
if (this.sessionToken)
return Observable.of(this.sessionToken);
else if(this.sessionObservable)
return this.sessionObservable;
else {
// simulate http call
this.sessionObservable = Observable.of(this.sessonTokenResponse)
.map(res => {
this.sessionObservable = null;
return res.headers["X-Session-Token"];
})
.delay(500)
.share();
return this.sessionObservable;
}
}
和getData获取该observable并附加到它。
public getData() {
if (this.dataObservable)
return this.dataObservable;
else {
this.dataObservable = this.sessionService.getSession()
.switchMap((sessionToken:string, index:number) =>{
//simulate data http call that needed sessionToken
return Observable.of(this.dataResponse)
.map(res => {
this.dataObservable = null;
return res.body;
})
.delay(1200)
})
.map ( data => {
return data;
})
.catch(err => {
console.log("err in data service", err);
// return err;
})
.share();
return this.dataObservable;
}
}
您仍然需要一个flatmap来组合不依赖的observable。
Plunkr:http://plnkr.co/edit/hiA1jP?p=info
我有想法使用切换地图:http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html