Реалізація кешування даних в мобільному додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Реалізація кешування даних в мобільному додатку
Середній
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Реалізація кешування даних в мобільному додатку

Додаток без кешування — це додаток, який при кожному переході на екран робить сітьовий запит. Повільний інтернет, немає інтернету, дорогий мобільний трафік — користувач видить спіннер або пустий екран. Кешування вирішує це, але правильна реалізація складніша, ніж здається: потрібно вирішити що кешувати, як довго, як інвалідувати та що показувати при помилці.

Шари кешування

Гарна архітектура кешу — це кілька рівнів:

Memory cache — у пам'яті процесу, найшвидший. Дані живуть до перезапуску додатка. Для зображень — NSCache на iOS (автоматично чиститься при memory pressure), LruCache на Android.

Disk cache — дані в файлах або локальній БД. Пережити перезапуск. Для API-відповідей — Room/SQLite з timestamp, для зображень — DiskLruCache всередину Coil/Glide.

Network — джерело правди, до якого звертаємось тільки коли потрібна свіжа.

Стратегія cache-first, refresh-in-background (stale-while-revalidate) — найзручніша для користувача: миттєво показуємо кеш, паралельно оновлюємо, якщо змінилось — перерисовуємо.

Кешування API-відповідей через Room

// Entity з timestamp для інвалідації
@Entity(tableName = "products_cache")
data class ProductCacheEntity(
    @PrimaryKey val id: String,
    val categoryId: String,
    val payload: String, // JSON-рядок
    val cachedAt: Long,  // Unix timestamp
    val etag: String? = null
)

// Repository: логіка cache-first
class ProductRepository(
    private val api: ProductApi,
    private val dao: ProductCacheDao,
    private val cacheMaxAge: Long = 5 * 60 * 1000L // 5 хвилин
) {
    fun getProductsByCategory(categoryId: String): Flow<List<Product>> = flow {
        // 1. Сразу видаємо кеш
        val cached = dao.getByCategory(categoryId)
        if (cached.isNotEmpty()) {
            emit(cached.map { it.toProduct() })
        }

        // 2. Перевіряємо свіжість
        val oldestEntry = cached.minOfOrNull { it.cachedAt } ?: 0L
        val needsRefresh = System.currentTimeMillis() - oldestEntry > cacheMaxAge

        if (needsRefresh || cached.isEmpty()) {
            try {
                val fresh = api.getProducts(categoryId)
                val entities = fresh.map { it.toCacheEntity(categoryId) }
                dao.upsertAll(entities)
                emit(fresh)
            } catch (e: IOException) {
                // Сітьа недоступна — кеш вже видан, нічого не робимо
                if (cached.isEmpty()) throw e // нічого показувати — пробрасуємо
            }
        }
    }
}

Цей паттерн — основа offline-first. UI підписаний на Flow, отримує дані дважди: спочатку кеш, потім свіжі.

ETag та Last-Modified

Замість time-based інвалідації можна використовувати HTTP-кеш заголовки. Сервер відправляє ETag: "v42", наступний запит відправляє If-None-Match: "v42" — якщо дані не змінилися, сервер повертає 304 без тіла. Економить трафік.

OkHttp (базовий HTTP-клієнт для Android і React Native) підтримує HTTP-кеш з коробки:

val cache = Cache(
    directory = File(context.cacheDir, "http-cache"),
    maxSize = 10L * 1024 * 1024 // 10 МБ
)

val client = OkHttpClient.Builder()
    .cache(cache)
    .build()

Для iOS URLSession підтримує URLCache аналогічно. Але HTTP-кеш працює тільки якщо сервер відправляє правильні Cache-Control заголовки — якщо бекенд відправляє Cache-Control: no-store, кеш не спрацює незалежно від налаштувань клієнта.

Кешування зображень

Для зображень готові бібліотеки вирішують завдання краще за будь-яку самоділку:

  • Android: Coil 2.x — Kotlin-first, Compose-ready, memory + disk cache, placeholder/error states
  • iOS: SDWebImage або Kingfisher — async загрузка, NSCache + disk, progressive JPEG
  • React Native: react-native-fast-image (обгортка над SDWebImage/Glide)
// Coil у Compose
AsyncImage(
    model = ImageRequest.Builder(context)
        .data(product.imageUrl)
        .memoryCacheKey(product.id)
        .diskCacheKey(product.imageUrl)
        .crossfade(true)
        .build(),
    contentDescription = product.title,
    placeholder = painterResource(R.drawable.placeholder),
    error = painterResource(R.drawable.error_image)
)

Інвалідація кешу

Найскладніша частина. Стратегії:

  • TTL (Time To Live) — кеш живе N хвилин, потім застарів. Просто, передбачуваний.
  • Event-based — сервер відправляє push при змінах даних → інвалідуємо конкретний кеш. Точно, але вимагає серверної підтримки.
  • Version-based — при кожній відповіді сервер відправляє dataVersion, клієнт порівнює з збереженим.
  • Pull-to-refresh — користувач явно запитує оновлення. Завжди потрібен як fallback.

Реалізація багаторівневого кеша з Room + HTTP-кеш + інвалідація: 1–2 тижні залежно від кількості типів даних. Вартість розраховується індивідуально.