I read dozens of tutorial and Stackoverflow answers to my problem but nothing is working for me! Also, most of them are old so probably OKHTTP changed somehow.
All I want is to enable offline caching for Retrofit.
I am using GET
I tried using only offlineCacheInterceptor
as an Interceptor, but I kept getting:
Unable to resolve host "jsonplaceholder.typicode.com": No address associated with hostname
I tried using a combination of offlineCacheInterceptor
as an Interceptor + provideCacheInterceptor()
as a NetworkInterceptor, but I kept getting:
504 Unsatisfiable Request (only-if-cached) and a null response.body()
I even made sure to add .removeHeader("Pragma")
everywhere!
I tried all these Links:
https://newfivefour.com/android-retrofit2-okhttp3-cache-network-request-offline.html (One interceptor, Not working!!)
https://medium.com/mindorks/caching-with-retrofit-store-responses-offline-71439ed32fda (One interceptor, Not working!)
https://caster.io/lessons/retrofit-2-offline-cache (Separate Online + Offline caching, Not working)
https://www.journaldev.com/23297/android-retrofit-okhttp-offline-caching (Not working, 504 Unsatisfiable Request (only-if-cached))
http://mikescamell.com/gotcha-when-offline-caching-with-okhttp3/ (One interceptor, Not working!!)
https://stackoverflow.com/a/48295397/8086424 (Not Working) Unable to resolve host "jsonplaceholder.typicode.com": No address associated with hostname
Can Retrofit with OKHttp use cache data when offline (TOO confusing!)
Here's my code:
public static Retrofit getRetrofitInstance(Context context) {
if (retrofit == null) {
c = context;
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(context.getCacheDir(), cacheSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(provideHttpLoggingInterceptor())
.addInterceptor(offlineCacheInterceptor)
.addNetworkInterceptor(provideCacheInterceptor())
.cache(cache)
.build();
//////////////////////////
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
}
return retrofit;
}
public static Interceptor offlineCacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.e("bbbb", "bbbb");
if (!checkInternetAvailability()) {
Log.e("aaaaa", "aaaaaa");
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(30, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.removeHeader("Pragma")
.build();
}
return chain.proceed(request);
}
};
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.removeHeader("Pragma")
.build();
}
};
}
I am using jsonplaceholder.typicode.com/photos that returns:
content-type: application/json; charset=utf-8
date: Sun, 21 Oct 2018 14:26:41 GMT
set-cookie: __cfduid=d9e935012d2f789245b1e2599a41e47511540132001; expires=Mon, 21-Oct-19 14:26:41 GMT; path=/; domain=.typicode.com; HttpOnly
x-powered-by: Express
vary: Origin, Accept-Encoding
access-control-allow-credentials: true
expires: Sun, 21 Oct 2018 18:26:41 GMT
x-content-type-options: nosniff
etag: W/"105970-HCYFejK2YCxztz8++2rHnutkPOQ"
via: 1.1 vegur
cf-cache-status: REVALIDATED
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 46d466910cab3d77-MXP
Cache-Control: public, max-age=60
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.
So, today I will explain how you can implement online & offline caching using Retrofit & OKHTTP with clear steps + How to test and know whether you are getting the data from cache or network.
If you are getting a
504 Unsatisfiable Request (only-if-cached)
OR anUnable to resolve host "HOST": No address associated with hostname
then you can use any of the following solutions.Before you begin, you must always remember to:
.removeHeader("Pragma")
as shown below (This lets you override the server's caching protocol)N.B: If you want to depend on your server's caching protocol for online and offline caching, then don't read the 2 solutions. Just read this article. All you need is to create a cache object and attache it to OKHTTPClient object.
Solution 1: (Longer, but you have full control)
Step 1: (Create onlineInterceptor)
Step 2: (Create Offline Interceptor) (Only if you want cache access when offline)
Step 3: (Create a cache object)
Step 4: (Add interceptors and cache to an OKHTTPClient object)
Step 5:(If you are using Retrofit, add the OKHTTPClient object to it)
DONE!
Solution 2: (Just use a library to do all that for you! But deal with the limitations)
Use OkCacheControl library
Step 2 (Create an OKHTTPClient object)
Step 3:(Attach the OKHTTPClient object to Retrofit as shown above)
Step 4: (Create a NetworkMonitor Object)
DONE!
Testing: In order to know whether your device is getting data from the network or from cache, simply add the following code to your
onResponse
method of Retrofit.If the device is using the Network, you will get "response came from server".
If device is using Cache, you will get both of the above responses! For more info about this read this article.
For more info about using OKHTTP interceptors go to this page.