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 wan
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 an Unable 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)
static Interceptor onlineInterceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response response = chain.proceed(chain.request());
int maxAge = 60; // read from cache for 60 seconds even if there is internet connection
return response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
}
};
Step 2: (Create Offline Interceptor) (Only if you want cache access when offline)
static Interceptor offlineInterceptor= new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isInternetAvailable()) {
int maxStale = 60 * 60 * 24 * 30; // Offline cache available for 30 days
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return chain.proceed(request);
}
};
Step 3: (Create a cache object)
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(context.getCacheDir(), cacheSize);
Step 4: (Add interceptors and cache to an OKHTTPClient object)
OkHttpClient okHttpClient = new OkHttpClient.Builder()
// .addInterceptor(provideHttpLoggingInterceptor()) // For HTTP request & Response data logging
.addInterceptor(OFFLINE_INTERCEPTOR)
.addNetworkInterceptor(ONLINE_INTERCEPTOR)
.cache(cache)
.build();
Step 5:(If you are using Retrofit, add the OKHTTPClient object to it)
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
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)
OkHttpClient okHttpClient = OkCacheControl.on(new OkHttpClient.Builder())
.overrideServerCachePolicy(1, MINUTES)
.forceCacheWhenOffline(networkMonitor)
.apply() // return to the OkHttpClient.Builder instance
//.addInterceptor(provideHttpLoggingInterceptor())
.cache(cache)
.build();
Step 3:(Attach the OKHTTPClient object to Retrofit as shown above)
Step 4: (Create a NetworkMonitor Object)
static OkCacheControl.NetworkMonitor networkMonitor=new
OkCacheControl.NetworkMonitor() {
@Override
public boolean isOnline() {
return isInternetAvailable();
}
};
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.
public void onResponse(Call<List<RetroPhoto>> call, Response<List<RetroPhoto>> response) {
if (response.raw().cacheResponse() != null) {
Log.e("Network", "response came from cache");
}
if (response.raw().networkResponse() != null) {
Log.e("Network", "response came from server");
}
}
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.