简体   繁体   English

RxJava 使用 observables 为 android 构建缓存

[英]RxJava building cache with observables for android

I'm having a hard time understanding on how to build a cache using RxJava.我很难理解如何使用 RxJava 构建缓存。 The idea is that I need to either get data from a memory cache or load from my database (dynamoDb).这个想法是我需要从内存缓存中获取数据或从我的数据库 (dynamoDb) 加载。 However, this cache is supposed to be shared across fragments and or threads.但是,这个缓存应该在片段和/或线程之间共享。 So I need to return existing observables that are currently running and not finished.因此,我需要返回当前正在运行但尚未完成的现有 observable。 This allows threads to catch up and not do unnecessary work.这允许线程赶上而不是做不必要的工作。 I'm new to RxJava so this is what I have in mind as a sketch (missing some code for brevity):我是 RxJava 的新手,所以这就是我想到的草图(为简洁起见,缺少一些代码):

public class DBCache<K, T> {
private final ConcurrentHashMap<K, Set<T>> resultCache = new ConcurrentHashMap<>;
private final ConcurrentHashMap<K, Observable<Set<T>>> observableCache = new ConcurrentHashMap<>;

private Observable<Set<T>> getFromCache(final DynamoDbCacheKey<K, T> query) {
    return Observable.create(new Observable.OnSubscribe<Set<T>>() {
        @Override
        public void call(Subscriber<? super Set<T>> subscriber) {
        Set<T> results = resultCache.get(query.getKey());
        if (results != null && results.size() > 0) {
            subscriber.onNext(results);
        }
        subscriber.onCompleted();
        }
    });
}

public Observable<Set<T>> get(final QueryCacheKey<K, T> query){
    Observable<Set<T>> cachedObservable = observableCache.get(query.getKey());
    if (cachedObservable != null) {
        return cachedObservable;
    }
    Observable<Set<T>> observable = Observable
        .concat(getFromCache(query), getFromNetwork(query))
        .first()
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .cache();
    observableCache.putIfAbsent(query.getKey(), observable);
return observable;
} 

private Observable<Set<T>> getFromNetwork(final QueryCacheKey<K, T> query) {
    return Observable.create(new Observable.OnSubscribe<Set<T>>() {
    @Override
    public void call(Subscriber<? super Set<T>> subscriber) {
        try {
            Set<T> results = loadFromDb(query); //omitted
            resultCache.putIfAbsent(query.getKey(), results);
            subscriber.onNext(results);
            subscriber.onCompleted();
            observableCache.remove(query.getKey());
        } catch (Exception exception) {
            subscriber.onError(exception);
        }
    }
    });
} 

} }

Is there a better way to achieve this through RxJava (Not interested in caching strategies).有没有更好的方法通过 RxJava 实现这一点(对缓存策略不感兴趣)。 Any thoughts?有什么想法吗?

Here is a simple example of doing caching and retrieving a value once:下面是一个简单的缓存和检索值的例子:

public class RxCache<K, V> {

    final ConcurrentHashMap<K, AsyncSubject<V>> cache;

    final Func1<K, Observable<V>> valueGenerator;

    public RxCache(Func1<K, Observable<V>> valueGenerator) {
        this.valueGenerator = valueGenerator;
        this.cache = new ConcurrentHashMap<>();
    }

    public Observable<V> get(K key) {
        AsyncSubject<V> o = cache.get(key);
        if (o != null) {
            return o;
        }

        o = AsyncSubject.create();

        AsyncSubject<V> p = cache.putIfAbsent(key, o);
        if (p != null) {
            return p;
        }

        valueGenerator.call(key).subscribe(o);

        return o;
    }

    public void remove(K key) {
        cache.remove(key);
    }
}

If you have multiple values, replace AsyncSubject with ReplaySubject .如果您有多个值,请将AsyncSubject替换为ReplaySubject

You can apply caching using BehaviorSubject , you create an Observable and then convert it to BehaviorSubject , then subscribe to this Subject to fetch your data.您可以使用BehaviorSubject应用缓存,创建一个Observable ,然后将其转换为BehaviorSubject ,然后订阅此Subject以获取您的数据。

Now this Subject will react as an Observable , when subscribed to it will give you the latest data fetched, and will emit new data when it is updated.现在这个Subject将作为一个Observable做出反应,当订阅它时,它会给你获取的最新数据,并在更新时发出新数据。

See more details and implementation here: https://medium.com/@jaerencoathup/repository-pattern-using-rxjava-and-room-4ce79e4ffc5c在此处查看更多详细信息和实施: https : //medium.com/@jaerencoathup/repository-pattern-using-rxjava-and-room-4ce79e4ffc5c

Another approach: https://medium.com/@elye.project/rxjava-clean-way-of-prefetching-data-and-use-later-54800f2652d4另一种方法: https : //medium.com/@elye.project/rxjava-clean-way-of-prefetching-data-and-use-later-54800f2652d4

Learn more about Subjects with simple examples: https://blog.mindorks.com/understanding-rxjava-subject-publish-replay-behavior-and-async-subject-224d663d452f通过简单示例了解更多关于 Subjects: https : //blog.mindorks.com/understanding-rxjava-subject-publish-replay-behavior-and-async-subject-224d663d452f

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

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