重新使用observables来处理正在进行的API请求

时间:2015-10-18 04:06:02

标签: java android rx-java

我有一个组件A,它自己查询API并使用RX将结果存储在缓存中:

List<Data> cache = ...;

void queryData(int parameter) {
    myApi.getData(parameter).subscribe(data => cache.add(data));
}

现在,我想从其他组件中查询此缓存。在缓存未命中时,我希望该设计允许重新使用机上订阅(如果存在)。这是为了避免重复相同的请求。

我正在考虑将Observable存储在单独的缓存中(仍在我的组件A中)。

List<Observable<Data>> requestCache = ...;

public Observable<Data> getData(int parameter) {
    // if cache contains data, return new observable that emits that item

    // if cache does not contain data, check if requestCache contains the Observable I need. If so, return it.

    // if all else fails, return queryData(parameter)

} 

我需要将我原来的queryData修改为:

Observable<Data> queryData(int parameter) {
    Observable<Data> observable = myApi.getData(parameter);

    requestCache.add(observable);

    observable.subscribe(data => cache.add(data));
    observable.subscribe(data => requestCache.remove(observable));

    return observable;
}

这将完全隐藏这些请求到其他组件的缓存/飞行复杂性。但是,我想知道RX中是否有内置的方法来处理这个问题。

我是在正确的轨道上还是有更好的模式?

1 个答案:

答案 0 :(得分:4)

没有内置的方法可以做到这一点。以下是我将如何解决这个问题:

public final class ReactiveCache<K, V> {
    final Map<K, Observable<V>> requests = new HashMap<>();

    final Function<K, Observable<V>> generator;

    public ReactiveCache(Function<K, Observable<V>> generator) {
        this.generator = generator;
    }

    public Observable<V> get(K key) {
        ConnectableObservable<V> result;
        synchronized (requests) {
            Observable<V> current = requests.get(key);
            if (current != null) {
                return current;
            }

            result = generator.apply(key)
                    .doOnTerminate(() -> {
                        synchronized (requests) {
                            requests.remove(key);
                        }
                    })
                    .replay();

            requests.put(key, result);
        }

        return result.autoConnect(0);
    }
}

在这个类中,当你调用get()并且有一个正在进行中的observable时,你可以加入它并接收它的所有值。如果没有,或者飞行中已经完成,你将启动一个新的Observable。