RxJava2 flatMap创建重复事件

时间:2017-02-16 16:49:53

标签: java android rx-java rx-java2

我在RxJava2上比较新,而且我得到了一些奇怪的行为,所以很可能我错误地使用了这个工具。

这是一个相当大的项目,但我已将下面的代码段分开作为最低可重现代码:

Observable
  .interval(333, TimeUnit.MILLISECONDS)
  .flatMap(new Function<Long, ObservableSource<Integer>>() {
    private Subject<Integer> s = PublishSubject.create();
    private int val = 0;

    @Override public ObservableSource<Integer> apply(Long aLong) throws Exception {
      val++;
      s.onNext(val);
      return s;
      }
    })
  .subscribe(new Consumer<Integer>() {
    @Override public void accept(Integer integer) throws Exception {
      Log.w("value: %s", integer);
     }
  });

此代码使用.interval模拟来自我的rx流的事件,flatMap接收这些事件&#34;进行一些处理&#34;并使用Subject将结果推送到流中。

流是一个持续的过程,将有几个事件。

这个最低限度的代码很愚蠢,因为我只推动apply回调,但在实际案例中,有几个可能发生推送的时刻和收到的事件数量期间apply与通过主题发送的金额不同。

我期望看到的代码是:

value: 2  // 1 got skipped because onNext is called before there's a subscriber.
value: 3
value: 4
value: 5
value: 6 ... etc

我实际得到的是:

value: 2
value: 3
value: 3 // 3 twice
value: 4
value: 4
value: 4 // 4 repeated 3 times
value: 5
value: 5
value: 5
value: 5 // 5 repeated 4 times
value: 6
value: 6
value: 6
value: 6
value: 6 // 6 repeated 5 times
 ... etc

我还试图获得Observable<Integer> o = s.share();并将其返回,或直接返回s.share();并获得相同的结果。

我有点理解为什么会这样。 ObservableSource再次n再次订阅n,因此每次循环都会有更多事件。

问题:

我如何实现预期的行为?

(如果我的预期行为不明确,请在评论中提出更多意见)

3 个答案:

答案 0 :(得分:1)

您的PublishSubject多次订阅 ,每个项目间隔一次()。

修改:您需要每次都传递一个新的PublishSubject(如果您想要保留第一个/最后一个发射,请切换到BehaviorSubject);将其传递给长时间运行的进程,并确保在长时间运行的进程完成时正确调用其onComplete

答案 1 :(得分:1)

修改

在最近的评论之后,我可以想出这种解决方案:

class MyBluetoothClient {
  private PublishSubject<BTLEEvent> statusPublishSubject = PublishSubject.create()

  public Observable<BTLEEvent> getEventObservable() {
    return statusPublishSubject
  }

  private void publishEvent(BTLEEvent event) {
    statusPublishSubject.onNext(event)
  }

  public void doStuff1() {
    // do something that returns:
    publishEvent(BTLEEvent.someEvent1)
  }

  public void doStuff2() {
    // do something else that eventually yields
    publishEvent(BTLEEvent.someEvent2)
  }
}

你以这种方式使用它:

MyBluetoothClient client = MyBluetoothClient()
client
  .getEventObservable()
  .subscribe( /* */ )

///

client.doStuff1()

/// 

client.doStuff2

原始回答

这会吗?

Observable
  .interval(333, TimeUnit.MILLISECONDS)
  .flatMap(new Function<Long, ObservableSource<Integer>>() {
    private int val = 0;

    @Override public ObservableSource<Integer> apply(Long aLong) throws Exception {
      val++;
      return Observable.just(val);
      }
    })
  .subscribe(new Consumer<Integer>() {
    @Override public void accept(Integer integer) throws Exception {
      Log.w("value: %s", integer);
     }
  });

答案 2 :(得分:0)

所以这就是我想出的答案。我将@Tassos的答案标记为正确,因为他指出了我正确的道路。

首先我需要一个CachedSubject(一个缓存项目的主题,而没有观察者并在观察者连接后立即发送它们),这对于确保{{1}内的排放是必要的。真的通过了。该课主要包装apply

PublishSubject

然后我将这个类与class CachedSubject<T> extends Subject<T> { private PublishSubject<T> publishSubject = PublishSubject.create(); private Queue<T> cache = new ConcurrentLinkedQueue<>(); @Override public boolean hasObservers() { return publishSubject.hasObservers(); } @Override public boolean hasThrowable() { return publishSubject.hasThrowable(); } @Override public boolean hasComplete() { return publishSubject.hasComplete(); } @Override public Throwable getThrowable() { return publishSubject.getThrowable(); } @Override protected void subscribeActual(Observer<? super T> observer) { while (cache.size() > 0) { observer.onNext(cache.remove()); } publishSubject.subscribeActual(observer); } @Override public void onSubscribe(Disposable d) { publishSubject.onSubscribe(d); } @Override public void onNext(T t) { if (hasObservers()) { publishSubject.onNext(t); } else { cache.add(t); } } @Override public void onError(Throwable e) { publishSubject.onError(e); } @Override public void onComplete() { publishSubject.onComplete(); } }

一起使用
switchMap

这实际上允许我在Observable .interval(1000, TimeUnit.MILLISECONDS) .switchMap(new Function<Long, ObservableSource<Integer>>() { private Subject<Integer> s = new CachedSubject<>(); private int val = 0; @Override public ObservableSource<Integer> apply(Long aLong) throws Exception { val++; s.onNext(val); return s; } }) .subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.w("value: %s", integer); } }); 方法上接收任意数量的事件,只有1 apply<T t>订阅它,从中接收所有事件。