Detect if OkHttp response comes from cache (with Retrofit)

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.


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.cacheResponse != null) {
            // from cache
        } else if (response.networkResponse != null) {
            // from network
        }
        return response;
});

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;
    }
});

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;
}