Кеш та синхронізація даних у мобільній розробці: що це, які стратегії та як працює

Автор: IT Sectr Опубліковано: 2026-06-19 Час читання: 12 хв

У мобільній розробці робота з даними, кешування та синхронізація — три ключові аспекти, що визначають продуктивність і надійність додатка. Згідно з Google Android Architecture Guide, правильна архітектура обробки даних безпосередньо впливає на швидкість відгуку та користувацький досвід. Патерн Repository забезпечує єдину точку доступу до всіх джерел даних.

Головне

  • Repository — єдине джерело даних, що приховує деталі реалізації Remote та Local Data Source
  • LRU Cache — алгоритм кешування, що витісняє найменш нещодавно використані елементи при досягненні ліміту
  • Offline Queue — механізм відкладеного виконання операцій, коли пристрій перебуває без мережі
  • Conflict Resolution — стратегія вирішення конфліктів при синхронізації між кількома пристроями
  • Schema Migration — процес безпечної зміни структури локальної бази даних без втрати інформації

Робота з даними в мобільних додатках: патерн Repository та Data Source

Патерн Repository — архітектурний підхід, при якому єдиний клас-репозиторій керує всіма операціями з даними, абстрагуючи віддалені REST API та локальне сховище Room або SwiftData. Така робота з даними дозволяє додатку отримувати інформацію спочатку з Memory Cache або Disk Cache, а потім із мережі, скорочуючи час відгуку. У мобільній розробці Repository став стандартом де-факто завдяки рекомендаціям Google та Apple.

Remote Data Source та Local Data Source

Remote Data Source надає актуальну інформацію з сервера через HTTP-запити. Local Data Source — локальне сховище на пристрої, реалізоване через Room на Android або SwiftData на iOS. Репозиторій об'єднує обидва джерела: спочатку перевіряє локальний кеш, а при відсутності даних запитує віддалений API. Така організація роботи з даними дає додатку можливість функціонувати в офлайн-режимі та знижує навантаження на сервер.

Приклад Repository на Kotlin

kotlin
class UserRepository(
    private val remoteDataSource: UserRemoteDataSource,
    private val localDataSource: UserLocalDataSource
) {
    suspend fun getUsers(): List<User> {
        localDataSource.getCachedUsers()?.let { return it }
        val users = remoteDataSource.fetchUsers()
        localDataSource.cacheUsers(users)
        return users
    }
}

Приклад Repository на Swift

swift
class UserRepository {
    private let remote: UserRemoteDataSource
    private let local: UserLocalDataSource
    
    func getUsers() async throws -> [User] {
        if let cached = await local.getCached() { return cached }
        let users = try await remote.fetch()
        await local.save(users)
        return users
    }
}

Кешування даних: LRU Cache, Disk Cache та Memory Cache

LRU Cache (Least Recently Used) — алгоритм кешування, при якому при досягненні ліміту видаляється елемент, до якого найдовше не було звернень. У мобільних додатках LRU Cache застосовується для зображень, відповідей API та серіалізованих об'єктів. Правильне кешування даних скорочує кількість мережевих запитів і прискорює завантаження контенту. Кеш у мобільних додатках — обов'язковий компонент для високої продуктивності.

Memory Cache vs Disk Cache

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

Приклад реалізації LRU Cache

kotlin
class MemoryCache<K, V>(
    private val maxSize: Int = 100
) {
    private val cache = LinkedHashMap<K, V>(0, 0.75f, true)

    fun get(key: K): V? = cache[key]

    fun put(key: K, value: V) {
        if (cache.size >= maxSize) {
            cache.remove(cache.keys.first())
        }
        cache[key] = value
    }
}

Стратегії інвалідації кешу

TTL-кеш (Time To Live) автоматично видаляє запис через заданий інтервал часу — підходить для даних API. Event-driven інвалідація очищає кеш при отриманні push-повідомлення про зміни. У мобільних додатках вибір стратегії кешування залежить від типу даних: зображення кешуються надовго, а новинна стрічка потребує частої інвалідації. Coil на Android та Kingfisher на iOS уже вбудували LRU Cache для роботи із зображеннями.

Офлайн-черга: Offline Queue та Sync Manager

Offline Queue — структура даних, що зберігає операції користувача (створення, оновлення, видалення) у локальній базі, коли пристрій офлайн. При відновленні з'єднання Sync Manager послідовно застосовує ці операції до сервера. Така синхронізація даних гарантує, що жодна зміна не загубиться при тимчасовій втраті мережі. У мобільній розробці Offline Queue — критичний компонент для додатків із нестабільним з'єднанням.

Архітектура Offline Queue

Черга будується на таблиці в Room або SwiftData з полями: тип операції, JSON-тіло запиту, часова мітка та статус. Sync Manager — фоновий сервіс, який обробляє невиконані операції, відправляє їх на сервер, оновлює статус та видаляє успішні записи. Синхронізація даних через WorkManager на Android або BGTaskScheduler на iOS виконується навіть після перезавантаження пристрою. Використання Offline Queue в парі з грамотною роботою з даними забезпечує безшовний користувацький досвід.

Приклад Offline Queue на Kotlin

kotlin
@Entity
data class SyncOperation(
    @PrimaryKey val id: Long,
    val endpoint: String,
    val method: String,
    val body: String,
    val createdAt: Long
)

class SyncManager(
    private val dao: SyncOperationDao,
    private val api: ApiService
) {
    suspend fun syncPending() {
        dao.getPendingOperations().forEach { op ->
            try {
                api.execute(op.endpoint, op.method, op.body)
                dao.delete(op.id)
            } catch (e: Exception) {
                // retry on next cycle
            }
        }
    }
}

Політика ретраїв та таймаути

Експоненціальна затримка між ретраями (1с, 2с, 4с, 8с) захищає сервер від лавинного навантаження та запобігає нескінченним повторам. Ліміт ретраїв — 5 спроб — запобігає переповненню черги. Синхронізація в мобільних додатках із підтримкою ідемпотентності на сервері дозволяє безпечно повторювати операції, уникаючи дублікатів. Це особливо важливо для фінансових транзакцій та замовлень.

Синхронізація даних: Conflict Resolution та Schema Migration

Conflict Resolution — набір стратегій для ситуацій, коли одні й ті самі дані змінено на різних пристроях одночасно. Базова синхронізація даних потребує вибору підходу: Last-Write-Wins (перемагає останній запис), версіонування (перемагає вища версія) або ручне вирішення. У складних сценаріях застосовуються CRDT (Conflict-Free Replicated Data Types), що гарантують математичну збіжність даних.

Стратегії вирішення конфліктів

Last-Write-Wins найпростіше в реалізації, але може втратити зміни користувача. Version Vector — кожен запис зберігає номер версії та ідентифікатор пристрою; конфлікт виникає при неспівпадінні версій. CRDT — найнадійніша, але складна стратегія: дані математично сходяться до єдиного стану без централізованого координатора. Синхронізація в мобільних додатках на основі CRDT використовується в спільному редагуванні Google Docs та синхронізації нотаток Notion.

Schema Migration: безпечне оновлення бази

При оновленні додатка структура локальної БД змінюється: додаються колонки, таблиці, індекси. Schema Migration — процес перетворення існуючої бази до нової схеми без втрати даних. Room підтримує міграції через клас Migration зі старою та новою версією. SwiftData використовує VersionedSchema для опису змін. Правильна синхронізація даних між версіями додатка потребує, щоб міграції були протестовані ідемпотентно.

Приклад Schema Migration в Room

kotlin
val migration1to2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE users ADD COLUMN avatar_url TEXT")
    }
}

@Database(
    entities = [User::class],
    version = 2
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

Приклад Conflict Resolution на Swift

swift
enum ConflictStrategy {
    case lastWriteWins
    case versionVector
    case crdt
}

struct VersionedDocument {
    let id: String
    let version: Int
    let data: Data
    let editedBy: String
    
    func resolve(with remote: VersionedDocument) -> VersionedDocument {
        return version >= remote.version ? self : remote
    }
}

Room та SwiftData для локального зберігання

Room — бібліотека Google для локального зберігання на Android, побудована поверх SQLite та яка надає анотації для декларативного опису запитів. SwiftData — фреймворк Apple для iOS, macOS, watchOS та visionOS, спадкоємець Core Data з лаконічним синтаксисом Swift Macro. Обидва інструменти вирішують завдання роботи з даними на пристрої, але з різними підходами до організації коду. Кеш у мобільних додатках часто будується саме на цих технологіях.

Room: DAO, Entities та Type Converters

Room використовує анотації @Entity для таблиць та @Dao для запитів. DAO інкапсулює всі SQL-операції з перевіркою на етапі компіляції — помилки синтаксису SQL виявляються до запуску. Type Converter перетворює складні типи (Date, List) у примітиви SQLite. Сучасна робота з даними в Android-додатках будується навколо Room + Flow, забезпечуючи реактивне оновлення UI при змінах у кеші або локальній БД.

SwiftData: @Model та @Query

SwiftData використовує макрос @Model для визначення сутностей та @Query для спостереження за даними. Фреймворк автоматично відстежує залежності та оновлює інтерфейс при змінах. Для міграції схеми застосовується VersionedSchema з описом усіх версій. Синхронізація даних між SwiftData та сервером реалізується через кастомний Sync Manager, підписаний на оновлення через @Query.

Приклад моделі на SwiftData

swift
@Model
final class UserModel {
    var id: String
    var name: String
    var email: String
    var updatedAt: Date
    
    init(id: String, name: String, email: String) {
        self.id = id
        self.name = name
        self.email = email
        self.updatedAt = Date()
    }
}

Порівняння Room та SwiftData

КритерійRoomSwiftData
ПлатформаAndroidApple (iOS, macOS, visionOS)
ОсноваSQLiteSQLite (Core Data stack)
СинтаксисАнотації KotlinSwift Macro
МіграціїКлас MigrationVersionedSchema
РеактивністьFlow / LiveDataProperty wrapper @Query
КроссплатформаТільки AndroidТільки Apple

Часті запитання

Що таке LRU Cache?

LRU Cache — алгоритм кешування, який при заповненні ліміту видаляє найменш нещодавно використаний елемент. Застосовується для зображень та API-даних у мобільних додатках.

Як працює Offline Queue?

Offline Queue зберігає операції користувача в локальній БД при відсутності мережі. Sync Manager виконує їх при відновленні з'єднання, гарантуючи доставку змін на сервер.

Що таке Conflict Resolution?

Conflict Resolution — стратегія вирішення конфліктів при синхронізації даних. Основні підходи: Last-Write-Wins, Version Vector та CRDT для розподілених систем.

Room чи SwiftData — що вибрати?

Для Android вибирайте Room — зріла бібліотека з перевіркою SQL на етапі компіляції. Для iOS — SwiftData з декларативним синтаксисом. Для кроссплатформних проєктів підійде SQLDelight або Realm.

Як часто виконувати синхронізацію?

Оптимальна синхронізація даних — при кожній зміні для критичних операцій і фонова кожні 15–30 хвилин для решти. Для миттєвої доставки використовуйте push-повідомлення.

Підсумки

  • Repository об'єднує Remote та Local Data Source, забезпечуючи єдину точку доступу при роботі з даними
  • LRU Cache з дворівневою системою Memory + Disk Cache скорочує мережеві запити та прискорює завантаження контенту
  • Offline Queue з Sync Manager гарантує доставку змін при тимчасовій втраті з'єднання
  • Conflict Resolution на основі Version Vector або CRDT запобігає втраті даних при паралельній синхронізації
  • Schema Migration забезпечує безпечне оновлення локальної БД без втрати користувацької інформації
  • Room з DAO та SwiftData з @Model — стандартні рішення для локального зберігання в мобільній розробці
  • Комплексний підхід до кешування та синхронізації даних — основа продуктивного мобільного додатка

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект