我看到ReactiveX(RxJava)有一个运算符timeout
,它将应用于订阅流中的每个项目。但我只想检查超时的第一个响应,而不关心以下响应的超时。如何使用RxJava的运算符优雅地实现此要求?
答案 0 :(得分:3)
这是一种更实用的方法。它在Scala中,但应转录为Java:
val myTimeout : Observable[Nothing] = Observable timer (10 seconds) flatMap (_ => Observable error new TimeoutException("I timed out!"))
myStream amb myTimeout
amb
运算符返回首先发出的observable的值。
答案 1 :(得分:2)
一种方法如下:
Observable<Response> respStream = respStream();
ConnectableObservable<Response> sharedRespStream = respStream.publish();
Observable<String> first = sharedRespStream.first().timeout(2, TimeUnit.SECONDS);
Observable<String> rest = sharedRespStream.skip(1);
Observable<String> result = first.mergeWith(rest);
sharedRespStream.connect();
result.subscribe(response -> handleResponse(response), error -> handleError(error));
代码是自我解释:共享响应以避免重复请求,对发出的第一项应用超时,并将其与第一项之后的项合并。
答案 2 :(得分:2)
最佳选择是使用timeout overload为每个项目返回一个超时可观察值,并且还有一个用于订阅(这是您感兴趣的那个)。
observable.timeout(
() -> Observable.empty().delay(10, TimeUnit.SECONDS),
o -> Observable.never()
)
我将解释,第一个func0将在subscribe上运行,并将发出一个空的observable(发出完整的)延迟了你想要的时间。 如果在任何物品到达之前经过的时间将会超时,就像您想要的那样。 第二个参数func1将决定项目之间的超时,这是你没有用的,所以我们只是从不通过(没有完成或做任何事情)
另一种选择是 按照Luciano的建议,你可以这样做:
public static class TimeoutFirst<T> implements Transformer<T,T> {
private final long timeout;
private final TimeUnit unit;
private TimeoutFirst(long timeout, TimeUnit unit) {
this.timeout = timeout;
this.unit = unit;
}
@Override
public Observable<T> call(Observable<T> observable) {
return Observable.amb(observable,
Observable.timer(timeout, unit).flatMap(aLong -> Observable.error(new TimeoutException("Timeout after " + timeout + " " + unit.name()))));
}
}
public static <T> Transformer<T, T> timeoutFirst(long timeout, TimeUnit seconds) {
return new TimeoutFirst<>(timeout, seconds);
}
使用amb。这是一个非常简洁的解决方案。
答案 3 :(得分:2)
@ndori答案的Kotlin扩展
fun <T> Observable<T>.timeoutFirstMessage(timeout: Long, unit: TimeUnit): Observable<T> {
return this.timeout<Long, Long>(
Observable.timer(timeout, unit),
Function { Observable.never<Long>() }
)
}
答案 4 :(得分:0)
@ndori答案的RxJava2版本
Observable.timeout(
Observable.empty().delay(10, TimeUnit.SECONDS),
o -> Observable.never()
)