我正在使用Interval运算符,即使在我的管道上发生异常,我仍希望继续发出项目。
所以我尝试使用onErrorResumeNext
在Exception的情况下发出一个项目。但是我发现在发出这个项目之后,间隔会停止发出更多的物品。
这是我的单元测试。
@Test
public void testIntervalObservableWithError() {
Subscription subscription = Observable.interval(50, TimeUnit.MILLISECONDS)
.map(time -> "item\n")
.map(item -> item = null)
.map(String::toString)
.onErrorResumeNext(t-> Observable.just("item with error emitted"))
.subscribe(System.out::print, t->{
System.out.println(t);
}
);
TestSubscriber testSubscriber = new TestSubscriber((Observer) subscription);
testSubscriber.awaitTerminalEvent(20000, TimeUnit.MILLISECONDS);
}
我对此行为感到困惑,为什么observable取消订阅,如果它收到来自onErrorResumeNext
SOLUTION:
经过一些解释后,我意识到当一个错误发生时,可观察的t完成了。所以我最终将可能有异常的observable包装到另一个observable中并使用flatMap。那么主要的Observable继续发射物品。
@Test
public void testIntervalObservableWithError() {
Observable.interval(100, TimeUnit.MILLISECONDS)
.map(time -> "item\n")
.flatMap(item -> Observable.just(item)
.map(String::toString))
.subscribe(System.out::print);
TestSubscriber testSubscriber = new TestSubscriber();
testSubscriber.awaitTerminalEvent(5000, TimeUnit.MILLISECONDS);
}
如果有任何操作员可以做我想知道的所有魔法。
Regrads
答案 0 :(得分:1)
RxJava流使用的合同是,一旦发出错误,就不应再发出任何项目。如果您的用例要求在错误之后流继续,那么您还需要将错误转换为onNext
发射。创建一个包装类型说ValueOrError<T>
并开始考虑Observable<ValueOrError<T>>
:
Observable<Integer> source = ...
Observable<ValueOrError<Integer>> o =
source.map(x -> {
try {
return new ValueOrError<>(mightThrow(x));
}
catch (Throwable e) {
return new ValueOrError<>(e);
});
答案 1 :(得分:1)
您的订阅会中断,因为触发onErrorResumeNext
时,您的上游已经完成了错误。而你只是发出一个项目而不是让异常进入下游。为了保持上游存活,你必须防止抛出异常。
对于您的特定示例,解决方案可以是这样的:
...
.map(time -> "item\n")
.map(item -> item = null)
.map(item -> {
try {
return item.toString();
} catch (NullPointerException e) {
return "item with error emitted";
})
//no onErrorResumeNext()
.subscribe ...
onErrorResumeNext
只是将项目错误替换为onComplete
。
答案 2 :(得分:1)
这是一个有效的示例,可使用onErrorResumeNext继续在错误时调用http服务。花了几个小时找到它应该如何工作(对RxJs来说是新的),但是最终从@Maksim Ostrovidov的评论中了解了它,因此将其发布在这里。 您可以通过在开发工具“网络标签”中切换离线复选框来在chrome中对其进行测试
import { DOCUMENT } from '@angular/common';
import { Component, Inject, OnDestroy, OnInit, Renderer2 } from '@angular/core';
@Component({ /* ... */ })
export class MyModalComponent implements OnInit, OnDestroy {
constructor (
@Inject(DOCUMENT) private document: Document,
private renderer: Renderer2,
) { }
ngOnInit(): void {
this.renderer.addClass(this.document.body, 'embedded-body');
}
ngOnDestroy(): void {
this.renderer.removeClass(this.document.body, 'embedded-body');
}
}