Реализация кэширования данных в мобильном приложении

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, прогрессивный 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 недели в зависимости от количества типов данных. Стоимость рассчитывается индивидуально.