I'm trying to use Retrofit & OKHttp to cache HTTP responses. I followed this gist and, ended up with this code:
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
HttpResponseCache httpResponseCache = null;
try {
httpResponseCache = new HttpResponseCache(httpCacheDirectory, 10 * 1024 * 1024);
} catch (IOException e) {
Log.e("Retrofit", "Could not create http cache", e);
}
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setResponseCache(httpResponseCache);
api = new RestAdapter.Builder()
.setEndpoint(API_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setClient(new OkClient(okHttpClient))
.build()
.create(MyApi.class);
And this is MyApi with the Cache-Control headers
public interface MyApi {
@Headers("Cache-Control: public, max-age=640000, s-maxage=640000 , max-stale=2419200")
@GET("/api/v1/person/1/")
void requestPerson(
Callback<Person> callback
);
First I request online and check the cache files. The correct JSON response and headers are there. But when I try to request offline, I always get RetrofitError UnknownHostException
. Is there anything else I should do to make Retrofit read the response from cache?
EDIT:
Since OKHttp 2.0.x HttpResponseCache
is Cache
, setResponseCache
is setCache
Cache with Retrofit2 and OkHTTP3:
NetworkUtils.isNetworkAvailable() static method:
Then just add client to the retrofit builder:
Original source: https://newfivefour.com/android-retrofit2-okhttp3-cache-network-request-offline.html
All of the anwsers above did not work for me. I tried to implement offline cache in retrofit 2.0.0-beta2. I added an interceptor using
okHttpClient.networkInterceptors()
method but receivedjava.net.UnknownHostException
when I tried to use the cache offline. It turned out that I had to addokHttpClient.interceptors()
as well.The problem was that cache wasn't written to flash storage because the server returned
Pragma:no-cache
which prevents OkHttp from storing the response. Offline cache didn't work even after modifying request header values. After some trial-and-error I got the cache to work without modifying the backend side by removing pragma from reponse instead of the request -response.newBuilder().removeHeader("Pragma");
Retrofit: 2.0.0-beta2; OkHttp: 2.5.0
...
...
My solution:
Edit for Retrofit 2.x:
OkHttp Interceptor is the right way to access cache when offline:
1) Create Interceptor:
2) Setup client:
3) Add client to retrofit
Also check @kosiara - Bartosz Kosarzycki's answer. You may need to remove some header from the response.
OKHttp 2.0.x (Check the original answer):
Since OKHttp 2.0.x
HttpResponseCache
isCache
,setResponseCache
issetCache
. So you shouldsetCache
like this:Original Answer:
It turns out that server response must have
Cache-Control: public
to makeOkClient
to read from cache.Also If you want to request from network when available, you should add
Cache-Control: max-age=0
request header. This answer shows how to do it parameterized. This is how I used it:building on @kosiara-bartosz-kasarzycki's answer, I created a sample project that properly loads from memory->disk->network using retrofit, okhttp, rxjava and guava. https://github.com/digitalbuddha/StoreDemo
The answer is YES, based on the above answers, I started writing unit tests to verify all possible use cases :
I built a small helper lib to configure OKHttp cache easily, you can see the related unittest here on Github : https://github.com/ncornette/OkCacheControl/blob/master/okcache-control/src/test/java/com/ncornette/cache/OkCacheControlTest.java
Unittest that demonstrates the use of cache when offline :
As you can see, cache can be used even if it has expired. Hope it will help.