简体   繁体   English

第一个元素之前的 RxJava Observable 超时

[英]RxJava Observable timeout before first element

I have device that send me ping, and I use observable for this.我有向我发送 ping 的设备,为此我使用了 observable。 But before first ping we start connection and it takes some time.但在第一次 ping 之前,我们开始连接,这需要一些时间。 Therefore I want first ping have 10 sec timeout.因此我希望第一次 ping 有 10 秒的超时。 I make it this way:我这样做:

public Observable<Ping> getPing() {
    ConnectableObservable<Ping> observable = device.connectToDevice().publish();

    Observable<Ping> firstWithTimeout = observable.take(1).timeout(10, TimeUnit.SECONDS);
    Observable<Ping> fromSecondWithoutTimeout = observable.skip(1);

    Observable<Ping> mergedObservable = firstWithTimeout.mergeWith(fromSecondWithoutTimeout)
            .doOnDispose(() -> disconnect(bluetoothDevice))
            .doOnError(error -> disconnect(bluetoothDevice));

    observable.connect();
    return mergedObservable;
}

For test I use为了测试我使用

Subject<Ping> observable = PublishSubject.create();
when(device.connect()).thenReturn(observable);
TestObserver<Ping> testSubscriber = TestObserver.create();
getPing.subscribe(testSubscriber);
observable.onNext(new Ping());

testSubscriber.assertValueCount(1);

This test will fail, because TimeoutException, in spite I send ping instantly.尽管我立即发送了 ping,但该测试将失败,因为 TimeoutException。

There is an overloaded timeout operator that will perfectly fit here:有一个重载的timeout操作符非常适合这里:

timeout(ObservableSource<U> firstTimeoutIndicator, Function<? super T, ? extends ObservableSource<V>> itemTimeoutIndicator)

Assuming that your observable reference is testObserable you simply do the:假设您的可观察引用是testObserable您只需执行以下操作:

testObservable.timeout(
        Observable.timer(5L, TimeUnit.SECONDS), // here you set first item timeout
        ignored -> Observable.never() // for other elements there is no time function
)

Please have a look at this setup:请看一下这个设置:

JUnit5 / RxJava2 JUnit5 / RxJava2

I think you error a incorrect configuration of the mock我认为你错误的模拟配置不正确

when(device.connect()).thenReturn(observable);当(device.connect()).thenReturn(observable);

Please have a look at my implementation.请看一下我的实现。 There is no need to use publish / connect when you are createing a new observable with every method-invocation.当您为每个方法调用创建新的 observable 时,无需使用发布/连接。 Use autoConnect in device for method-impl connectToDevice()在设备中使用 autoConnect for method-impl connectToDevice()

  Device device;

  @BeforeEach
  void setUp() {
    device = mock(Device.class);
  }

  @Test
  void name() throws Exception {
    Subject<Ping> observable = PublishSubject.create();

    when(device.connectToDevice()).thenReturn(observable);

    TestObserver<Ping> test = getPing(Schedulers.computation()).test();
    observable.onNext(new Ping());

    test.assertValueCount(1);
  }

  @Test
  void name2() throws Exception {
    Subject<Ping> observable = PublishSubject.create();

    when(device.connectToDevice()).thenReturn(observable);

    TestScheduler testScheduler = new TestScheduler();
    TestObserver<Ping> test = getPing(testScheduler).test();

    testScheduler.advanceTimeBy(20, TimeUnit.SECONDS);

    observable.onNext(new Ping());

    test.assertError(TimeoutException.class);
  }

  private Observable<Ping> getPing(Scheduler scheduler) {

    return device
        .connectToDevice()
        .take(1)
        .timeout(10, TimeUnit.SECONDS, scheduler)
        .doOnDispose(() -> disconnect())
        .doOnError(error -> disconnect());
  }

  private void disconnect() {}

  interface Device {
    Observable<Ping> connectToDevice();
  }

  class Ping {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM