在onErrorResumeNext之后,间隔继续工作

时间:2016-11-17 16:48:21

标签: java rx-java reactive

我正在使用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

3 个答案:

答案 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');
    }
}