Skip to content Skip to sidebar Skip to footer

Caching Network Calls Using Rxjava For Some Duration

I am making a network using Retorfit + RxJava2 and I want to cache the response for 30 seconds. Any calls made after 30 seconds interval should get the latest results from server.

Solution 1:

The are 2 problem with your approach:

  1. as @drhr mentioned, you are creating a new Observable each time you call service.getName() you're creating a new instance of Observable, you should keep the same replayed instance and give to the caller outside the same instance each time it calls service.getName().
  2. even if you will return the same instance, replay with 30 seconds, will replay the sequence emitted by the source Observable over the last 30 sec, meaning after cache expiration time, you will get nothing as your request happened more than 30 sec ago. it doesn't mean that the Observable will restart automatically after this period.

In order to cache for specific period, you basically need to invalidate the cached response after cache period, and perform new request after this period, that's mean you should control your subscribe, and do it there. You can achieve it with something like that:

publicclassCachedRequest<T> {

    privatefinalAtomicBooleanexpired=newAtomicBoolean(true);
    privatefinal Observable<T> source;
    privatefinallong cacheExpirationInterval;
    privatefinal TimeUnit cacheExpirationUnit;
    private Observable<T> current;

    publicCachedRequest(Observable<T> o, long cacheExpirationInterval,
                         TimeUnit cacheExpirationUnit) {
        source = o;
        current = o;
        this.cacheExpirationInterval = cacheExpirationInterval;
        this.cacheExpirationUnit = cacheExpirationUnit;
    }

    private Observable<T> getCachedObservable() {
        return Observable.defer(() -> {
            if (expired.compareAndSet(true, false)) {
                current = source.cache();
                Observable.timer(cacheExpirationInterval, cacheExpirationUnit)                          
                        .subscribe(aLong -> expired.set(true));
            }
            return current;
        });
    }
}

with defer you can return the right Observable according to cache expiration status, so every subscribe happened within the cache expiration will get cached Observable (using cache()) - meaning request will be performed only once. after cache expiration, additional subscribe will trigger new request and will set a new timer to reset the cache expiration.

Solution 2:

Try to look at okhttp interceptors.

Add CacheInterceptor:

publicclassCacheInterceptorimplementsInterceptor {
    @Overridepublic Response intercept(Chain chain)throws IOException {
        Responseresponse= chain.proceed(chain.request());

        CacheControlcacheControl=newCacheControl.Builder()
                .maxAge(30, TimeUnit.SECONDS)
                .build();

        return response.newBuilder()
                .removeHeader("Pragma")
                .removeHeader("Cache-Control")
                .header("Cache-Control", cacheControl.toString())
                .build();
    }
}

And add it and cache to your OkHttp Client like this:

FilehttpCacheDirectory=newFile(context.getCacheDir(), "http-cache");
intcacheSize=10 * 1024 * 1024; // 10 MiBCachecache=newCache(httpCacheDirectory, cacheSize);

OkHttpClienthttpClient=newOkHttpClient.Builder()
                               .addNetworkInterceptor(newCacheInterceptor())
                               .cache(cache)
                               .build();

Post a Comment for "Caching Network Calls Using Rxjava For Some Duration"