Retrofit Offline Caching in Android
In this blog, We are going to learn about how to achieve Retrofit Offline Caching in Android.
We know that OkHttp is the default HttpClient for Retrofit.
OkHttp comes with a powerful component Interceptors.
We have two types of interceptors.
- Application Interceptors – Gets you the final response.
- Network Interceptors – To intercept intermediate requests.
Using Interceptors you can read and modify the requests. And obviously, we’ll add Cache-control on the responses.
Cache-control is a header used to specify caching policies in client requests and server responses.
Note: You can only cache the GET requests.
Code :
The code for the MainActivity.kt is given below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
class MainActivity : AppCompatActivity() { var apiService: APIService? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setupRetrofitAndOkHttp() apiService?.getRandomJoke("random")?.enqueue(object : Callback<MyResponse>{ override fun onResponse( call: Call<MyResponse>, response: retrofit2.Response<MyResponse> ) { Log.d("TAG", "onResponse: "+response.body()) } override fun onFailure(call: Call<MyResponse>, t: Throwable) { Log.d("TAG", "onResponse: "+t.message) } }) } private fun setupRetrofitAndOkHttp() { val httpLoggingInterceptor = HttpLoggingInterceptor() httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY val httpCacheDirectory = File(cacheDir, "offlineCache") //10 MB val cache = Cache(httpCacheDirectory, 10 * 1024 * 1024) val httpClient = OkHttpClient.Builder() .cache(cache) .addInterceptor(httpLoggingInterceptor) .addNetworkInterceptor(provideCacheInterceptor()) .addInterceptor(provideOfflineCacheInterceptor()) .build() val retrofit: Retrofit = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(Gson())) .client(httpClient) .baseUrl(BASE_URL) .build() apiService = retrofit.create(APIService::class.java) } private fun provideCacheInterceptor(): Interceptor? { return Interceptor { chain -> var request: Request = chain.request() val originalResponse: Response = chain.proceed(request) val cacheControl: String? = originalResponse.header("Cache-Control") if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") || cacheControl.contains("must-revalidate") || cacheControl.contains("max-stale=0") ) { val cc = CacheControl.Builder() .maxStale(1, TimeUnit.DAYS) .build() request = request.newBuilder() .removeHeader("Pragma") .cacheControl(cc) .build() chain.proceed(request) } else { originalResponse } } } private fun provideOfflineCacheInterceptor(): Interceptor? { return Interceptor { chain -> try { return@Interceptor chain.proceed(chain.request()) } catch (e: Exception) { val cacheControl = CacheControl.Builder() .onlyIfCached() .maxStale(1, TimeUnit.DAYS) .build() val offlineRequest: Request = chain.request().newBuilder() .cacheControl(cacheControl) .removeHeader("Pragma") .build() return@Interceptor chain.proceed(offlineRequest) } } } } |
The code for the APIService.kt is given below:
1 2 3 4 5 6 7 8 9 10 |
interface APIService { @GET("{path}") fun getRandomJoke(@Path("path") path: String?): Call<MyResponse> companion object { const val BASE_URL = "https://api.chucknorris.io/jokes/" } } |
Note: Don’t forget to add Internet permission in your manifest file.
1 |
<uses-permission android:name="android.permission.INTERNET"/> |
Now we have done. Hope this blog will help you to achieve caching retrofit requests in android.