重新订阅热观察,除非它完成,然后缓存有限的时间

时间:2016-02-15 11:14:17

标签: rx-java reactive-programming observable

我有另一个经常遇到的问题,但无法解决问题并使用rxJava解决问题。

我有一个长时间运行的操作(一个可观察的)。我想要实现的是一个可观察到的:

  • 第一次订阅,启动长时间操作
  • 后续订阅者附加到observable(如果尚未完成)

这两个可以使用share解决,但还有两个要求:

  • 当所有订阅者取消订阅时,下一个订阅者仍应附加到已经长时间运行的操作(除非它已完成)。这是share让我失望的地方
  • 当长操作完成时,其结果将缓存一段时间。新观察员应立即收到completed通知。在指定的时间之后,所有重置,回到原点

现在我的长时间运行操作包含在一个observable中,我所能实现的只有三个第一点:多个订阅者共享订阅,即使所有订阅者都取消订阅也会运行,并且当它完成并且有人订阅时它会重新启动再次。但是,我仍然无法让它缓存结果,因此在observable完成后的100 ms内,所有新订阅者都会立即收到onCompleted回调:

private Observable<Integer> createObservable() {
    Observable<Integer> values = Observable.merge(
            Observable.just(10),
            Observable.just(50).delay(100, TimeUnit.MILLISECONDS),
            Observable.just(100).delay(200, TimeUnit.MILLISECONDS));

    return Observable.defer(() -> values)
        .subscribeOn(Schedulers.io())
        .publish()
        .autoConnect()
        .doOnCompleted(() ->
                Observable.timer(100, TimeUnit.MILLISECONDS)
                        .doOnCompleted(() -> this.observable = createObservable())
                        .subscribe());
}

我很感激任何提示

2 个答案:

答案 0 :(得分:2)

对于缓存,我会使用时间戳将结果保存到内存中。然后使用concat从缓存中获取结果,同时时间戳仍然有效。例如:

public static class WrappedResult {
    private final String value;
    private final long time;

    public WrappedResult(String value, long time) {
        this.value = value;
        this.time = time;
    }
}

private Observable<WrappedResult>  getLongRunningObservable() {
    return Observable.just("1")
            .map(s -> new WrappedResult(s, System.currentTimeMillis()))
            //save result to cache
            .doOnNext(pair -> mCache = pair);
}

private Observable<WrappedResult> getCachedResult() {
    return Observable.just(mCache);
}

public Observable<String> getObservable() {
    return Observable.concat(getCachedResult(), getLongRunningObservable())
            //use cache if it's not too old. otherwise perform long running operation again
            .first(wrappedResult -> System.currentTimeMillis() - wrappedResult.time <= TimeUnit.MILLISECONDS.toMillis(100))
            .map(wrappedResult -> wrappedResult.value)
            //continue with your implementation for ConnectableObservable
            ;
}

有关Loading data from multiple sources with RxJava

的更多信息

答案 1 :(得分:0)

未经测试,它可能会永远运行循环,所以买家要小心:

Observable.switchOnNext(
   defer(()-> ...)
   .cache() // or .share() if you don't mind about losing initial entries
   .concatMap(Observable.empty().delay(timeout));

这个观察者将永远不会发出onCompleted,正如我所期望的描述所假设的那样。如果您希望observable完成,则需要更复杂的东西 - 使用onCompleted()标记上次完成的时间并在defer()中使用它来确定是否需要新的observable或旧的observable是否足够。