Detect if OkHttp response comes from cache (with Retrofit)

那年仲夏 提交于 2019-12-20 17:41:32

问题


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

回答1:


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



回答2:


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



回答3:


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.




回答4:


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



回答5:


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



来源:https://stackoverflow.com/questions/41727750/detect-if-okhttp-response-comes-from-cache-with-retrofit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!