为Observable供应价值

时间:2014-09-28 01:02:44

标签: java rx-java

我是rxjava的新手,我遇到以下问题:

外部系统不定期地将对象丢弃到FIFO队列中。我需要一个每秒运行一次的Observable,从队列中获取一个项目(如果有的话)并将其发送给订阅者。

两个问题:

  • 在Observable处于活动状态时生成队列项,无法提前提供所有项目。队列可能为空,在这种情况下,Observable必须处于待机状态且不发出任何内容。 (如果在暂停后一个项目在队列中可用时,Observable会立即跳转,那将是很好的,但如果我们不想更频繁地轮询,那么队列可能也需要是一个Observable ,不知道怎么做。)

  • 外部系统必须能够完成Observable。我可以设置一个变量并从Observable中读取它,但是我想知道是否有更优雅的方法来做到这一点。

    LinkedList<Layer> queue = new LinkedList<Layer>(); // the queue
    boolean stopObservable = false; // the variable to stop the observable
    
    Observable.create(new Observable.OnSubscribe<Layer>() {
    
        @Override public void call(Subscriber<? super Layer> subscriber) {
            try {
                if (!queue.isEmpty()) {
                    Layer layer = queue.poll();
                    subscriber.onNext(layer);
                } else {
                    if (stopObservable) { subscriber.onCompleted(); }
                }
            } catch (Exception e) {
                subscriber.onError(e);
            }
        }
    
    }).somethingThatCreatesTheInterval().subscribeOnEtc.
    

对于间隔,我不能使用.sample(),因为它会删除项目,并且发出所有项目都很重要。

.throttleWithTimeout()看起来更好,但它似乎也放弃了项目。

rx非常酷,但很难进入。任何意见都赞赏。

2 个答案:

答案 0 :(得分:1)

当我需要定期轮询外部Web服务时,我做了类似的事情。

  1. 在时间间隔内,您可以继续timer;在每个tick的粒度为1s时,可观察链将轮询并可能选择一个层,如果该层为null则不会发出任何内容

    Observable.timer(0, 1, TimeUnit.SECOND)
        .flatMap(tick -> Observable.just(queue.poll()).filter(layer -> layer != null))
        .subscribe(layer -> System.out.format("The layer is : %s",  layer));
    
  2. 现在,如果您想要中止整个链,您可以添加takeUntil。因此,当您的外部系统想要停止时,它将在stopObservable中提交一些内容,这将停止后续订阅:

    // somewhere before
    PublishSubject stopNotifier = PublishSubject.create();
    
    // somewhere process the queue
    Observable.timer(0, 1, TimeUnit.SECOND)
        .takeUntil(stopNotifier)
        .flatMap(tick -> Observable.just(queue.poll()))
        .subscribe(layer -> System.out.format("The layer is : %s",  layer));
    
    // when not anymore interested (calling onComplete works too)
    stopNotifier.onNext("cancel everything about the queue");
    
  3. 我正在用平板电脑写这个回复,所以你可能会认为我可能拼错了一些单词或者编写了天真的编程错误;)

答案 1 :(得分:0)

如果可能,您应该使用PublishSubject<Layer>而不是LinkedList<Layer>。然后,外部系统可以通过调用publishSubject.onNext来提供新项目,并且由于PublishSubjectObservable的子类,因此您的系统可以将其视为Observable,并且取决于语义与关于你想要的时间,将其中一个运算符应用于它:

  • sample
  • debounce
  • throttleFirst / throttleLast / throttleWithTimeout
  • .zipWith(Observable.timer(1, TimeUnit.SECONDS), (value, tick) -> value)(可能会做很多缓冲!)
  • 根本没有时间修改(也考虑到这一点)