Кэширование относится к временному хранению данных, полученных из сети, в хранилище устройства, что позволяет нам получить к ним доступ позже, либо когда устройство находится в автономном режиме, либо когда нам нужно снова получить те же данные.

В этом блоге мы узнаем, как реализовать кеширование в вашем приложении для Android с помощью OkHttp Interceptor и Retrofit, что позволит вам временно хранить ответы для последующего использования без необходимости в базе данных!

Давайте рассмотрим, как кэширование может повысить производительность наших приложений для Android.

  • Когда мы запрашиваем данные с сервера через сетевой вызов,
  • первый запрос извлечет данные с сервера и сохранит ответ HTTP в кеше клиента.
  • Впоследствии, если мы снова сделаем тот же вызов API, он мгновенно вернет данные из кеша.

Приступим к практической части этой статьи.

В настоящее время мы используем такие модификации, как:

val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

Как мы знаем, приведенная выше модернизация использует OkHttpClient по умолчанию, который не использует кеш, поэтому нам нужно создать экземпляр OkHttpClient, который поддерживает кеширование и может эффективно обрабатывать выборку данных, когда:

  • Отсутствует подключение к Интернету,и
  • Приложению необходимо получить доступ к одним и тем же данным из сети в течение короткого периода времени.

Теперь давайте создадим дружественный к кэшу OkHttpClient.

Шаг 1. Создайте размер кэша и кэш.

 val cacheSize = (10 * 1024 * 1024).toLong() // 10MB 
 val myCache = Cache(context.cacheDir, cacheSize)

Шаг 2. Определите метод проверки подключения к Интернету

Нам нужен метод в нашем приложении, который проверяет подключение к Интернету. Это шаблонный код, но вот он,

fun hasNetwork(context: Context): Boolean? {
        var isConnected: Boolean? = false // Initial Value
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        if (activeNetwork != null && activeNetwork.isConnected)
            isConnected = true
        return isConnected
    }

Шаг 3: Давайте создадим перехватчик

OkHttp поставляется с мощным компонентом Interceptors.

У нас есть два типа перехватчиков:

  • Перехватчики приложений: это перехватчики, которые добавляются между кодом приложения (нашим письменным кодом) и базовой библиотекой OkHttp. Это те, которые мы добавляем с помощью addInterceptor().
  • Сетевые перехватчики. Это перехватчики, которые добавляются между основной библиотекой OkHttp и сервером. Их можно добавить в OkHttpClient с помощью addNetworkInterceptor().

теперь мы создадим перехватчик, как показано ниже:

// this for only response interceptor is invoked for online responses
 
val REWRITE_RESPONSE_INTERCEPTOR = Interceptor { chain ->
            val originalResponse = chain.proceed(chain.request())
            val maxAge = 60 // read from cache for 60 seconds even if there is internet connection
            val cacheControl = originalResponse.header("Cache-Control")
            if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
                cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")
            ) {
                originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, max-age=$maxAge")
                    .build()
            } else {
                originalResponse
            }
        }
 val REWRITE_RESPONSE_INTERCEPTOR_OFFLINE = Interceptor { chain ->
            var request = chain.request()
            if (!hasNetwork(context)) {
                val maxStale = 60 * 60 * 24 * 30 // Offline cache available for 30 days
                request = request.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, only-if-cached=$maxStale") // The 'only-if-cached' attribute indicates to not retrieve new data; fetch the cache only instead.
                    .build()
            }
            chain.proceed(request)
        }

Шаг 4. Создайте экземпляр OkHttpClient, определите кеш и добавьте перехватчики.

 val okHttpClient  = OkHttpClient.Builder().apply {
            cache(myCache)
            addInterceptor(REWRITE_RESPONSE_INTERCEPTOR_OFFLINE)
            addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
      }

Теперь нам нужно добавить этот только что созданный OkHttpClient в наш экземпляр Retrofit.

val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                // Adding our OkHttpClient
                .client(okHttpClient)
                .build()

Именно так мы можем кэшировать HTTP-ответы в Android, используя OkHttp Interceptor и Retrofit.

Спасибо за прочтение и счастливого кодирования! 😊

Не забывайте 👏