Detect if OkHttp response comes from cache (with Retrofit)

okhttp in memory cache
retrofit cache
okhttp dns cache
retrofit clear cache
retrofit cache not working
retrofit response interceptor
okhttp interceptor tutorial
multiple cache-control headers

Is there a way to detect if a Retrofit response comes from the configured OkHttp cache or is a live response?

Client definition:

Cache cache = new Cache(getCacheDirectory(context), 1024 * 1024 * 10);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .cache(cache)
            .build();

Api definition:

@GET("/object")
Observable<Result<SomeObject>> getSomeObject();

Example call:

RetroApi retroApi = new Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl(baseUrl)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(RetroApi.class);

result = retroApi.getSomeObject().subscribe((Result<SomeObject> someObjectResult) -> {
     isFromCache(someObjectResult); // ???
});

Any time you have an okhttp3.Response (retrofit2.Response.raw()), you can check if the response is from the cache.

To quote Jesse Wilson:

There are a few combos.

.networkResponse() only – your request was served from network exclusively.

.cacheResponse() only – your request was served from cache exclusively.

.networkResponse() and .cacheResponse() – your request was a conditional GET, so headers are from the network and body is from the cache.

So for your example, the isFromCache method would look like:

boolean isFromCache(Result<?> result) {
  return result.response().raw().networkResponse() == null;
}

Retrofit 2, Retrofit 2 — Check Response Origin (Network, Cache, or Both) how can you detect whether a response came from the cache, the server, or even both? This happens when Retrofit and OkHttp made a conditional request. Is there a way to detect if a Retrofit response comes from the configured OkHttp cache or is a live response? Client definition: Cache cache = new Cache(getCacheDirectory(context), 1024 * 1024 * 10); OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(cache) .build(); Api definition:

Solution 1:

By using the okhttp3.Response.cacheResponse() you can check if the response was received from the cache:

Returns the raw response received from the cache. Will be null if this response didn't use the cache

To get the raw OkHttp response from your retrofit Response obect use .raw(). i.e.:

public boolean isFromCache(Result<?> retroResult) {
    return retroResult.response().raw().cacheResponse() != null;
}

Solution 2:

You can add an Interceptor to the OkHttp Client via new OkHttpClient.Builder().addInterceptor(...). In this Interceptor retrieve the response via chain.proceed(chain.request). Then use Response.cacheResponse() respectively Response.networkResponse() to determine where the response came from.

Full code:

new OkHttpClient.Builder().addInterceptor(chain -> {
        Response response = chain.proceed(chain.request());
        if (response.cacheControl() != null) {
            // from cache
        } else if (response.networkResponse() != null) {
            // from network
        }
        return response;
});

Retrofit 2, The response is only the status code and header information and OkHttp will automatically apply Etag , Cache-Control , etc logic on That's all you have to do to support response caching with Retrofit. In the next tutorial, you'll learn how you can detect if a response came from the server, cache or both. Caching Requests. We know that OkHttp is the default HttpClient for Retrofit. OkHttp comes with a powerful component Interceptors. Interceptors are generally of two types: Application Interceptors – Gets you the final response. Network Interceptors – To intercept intermediate requests. Using Interceptors you can read and modify the requests.

if (response.raw().cacheResponse() != null) {  
    // true: response was served from cache
}

if (response.raw().networkResponse() != null) {  
    // true: response was served from network/server
}

But I would suggest you to check if your networkResponse is null, since once the request is cached and you have a networkResponse too, your response passed down the stream is from network and not cache(Depending on the maxStale you might have specified on CacheControl). So check if networkResponse is not null, if null and your cacheResponse is not null, the response is served from cache else vice versa.

Caching With Retrofit, In this article, I'll be talking about how to enable caching with Retrofit in of the OkHttpClient that is cache-enabled and can handle fetching the data efficiently when: Step 1: Define a method to check for internet connectivity. Caching Requests. We know that OkHttp is the default HttpClient for Retrofit. OkHttp comes with a powerful component Interceptors. Interceptors are generally of two types: Application Interceptors – Gets you the final response. Network Interceptors – To intercept intermediate requests. Using Interceptors you can read and modify the requests.

Too late but maybe this would be helpful for someone. When content comes from network: response.networkResponse() and response.cacheResponse() are not null, when content comes from cache response.networkResponse() is null, so code from @sebastian:

new OkHttpClient.Builder().addInterceptor(chain -> {
        Response response = chain.proceed(chain.request());
        if (response.cacheControl() != null) {
            // from cache
        } else if (response.networkResponse() != null) {
            // from network
        }
        return response;
});

just replace with this code:

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        if (response.networkResponse() != null) {
            Log.v(TAG, "Response from networkResponse(): " + response.networkResponse());
        } else if (response.cacheResponse() != null) {
            Log.v(TAG, "Response from cacheControl(): " + response.cacheResponse());
        }
        return response;
    }
});

cache response is stale · Issue #4539 · square/okhttp · GitHub, Hi, it seems like the cache response contains the old response while the /​41727750/detect-if-okhttp-response-comes-from-cache-with-retrofit  Good apps cache the API response to show up the recent content when it’s running out of internet or slow in connection. Gradle dependencies for Retrofit and OkHttp. Finally come up with

The response comes from cache if cacheResponse exists AND networkResponse (if exists) has a response code of 304. See: https://github.com/square/okhttp/issues/4539

Cache, Sometimes you'll want to show resources if they are available where a stale response is better than no response. Oct. 2018 (Retrofit 2.4 or OKHTTP 3.11) Complete Solution. Ok, so Online & Offline caching using OKHTTP or Retrofit has been causing so many problems for many people on stackoverflow and other forums. There are tons of misleading information and non-working code samples all over the internet.

Android Retrofit OkHttp Offline Caching, Why use both when OkHtttp caches the HTTP responses built-in? Caching Requests. We know that OkHttp is the default HttpClient for Retrofit. OkHttp comes  When the network request was a success, you've access to the response object. This is Retrofit's Response class, which won't reveal any information relevant to caching. However, you can go down a level by calling response.raw(), which gives you the network layers OkHttp's response object.

Consuming APIs with Retrofit, Retrofit is a type-safe REST client for Android, Java and Kotlin developed by Square. You will also need to update your OkHttp imports from import okhttp. find . -name '*.java' -exec gsed -i 's/import retrofit\./import retrofit2./g' \{\} + find . If you do not need any type-specific response, you can specify return value as simply  Retrofit has an excellent feature which lets developers cache responses for future use. Caching is ideally controlled by HTTP headers which are sent by the server in its response. You can read more about HTTP caching over here. The above approach to caching is what Retrofit uses and it works pretty well if the right headers are sent by the server.

Using OkHttp, It is also the underlying library for Retrofit library that provides type safety for be used to check the status code, the response body, and any headers that were For instance, if we wish to only retrieve the request if data is cached, we could  • In this lesson you will learn: How to use the OkHttp cache when you are offline How to add a Application Interceptor to OkHttp How to view/debug your OkHttp cache files Retrofit Documentation OkHttp Interceptors

Comments
  • Does this quotation come from a talk or some other online resource? If so, could you please provide a link?
  • It's actually better to check result.response().raw().cacheResponse() != null. If the client re-validates the cached response and receives a 304, both networkResponse() and cacheResponse() will be non-null.
  • Yes, depending on the semantics and what your desired app behavior is.
  • it's always indicating that the response comes from cache ! Even if I uninstall the application !
  • Solution 2 contains logical error. According to OkHttp documentation "cacheControl() is never null, even if this response contains no Cache-Control header"