Зображення — головна причина гальмувань у мобільних додатках. Ми не раз бачили, як скрол стрічки з аватарками смикається не тому, що пристрій слабкий, а тому що декодування JPEG відбувається на main thread у момент, коли комірка вже має відображатися. У мобільній розробці це часта проблема, і ми вирішуємо її за допомогою правильного багаторівневого кешу. Однак налаштування кешування зображень — нетривіальне завдання: навіть із популярними бібліотеками можна отримати промахи кешу, якщо не врахувати специфіку платформи та контенту.
Як працює багаторівневе кешування?
Багаторівневий кеш будується на двох рівнях: memory cache (L1) — швидкий, невеликий (20-30 МБ) та disk cache (L2) — повільніший, великий (200-500 МБ). Розміри підбираються виходячи з характеру контенту: у новинному додатку з великою кількістю унікальних зображень disk cache важливіший, у месенджері з аватарками — memory cache. Placeholder та error-state — окремо. Показувати пусте місце, поки завантажується картинка — гірше, ніж показувати скелетон. Error state має бути явним, але не ламати верстку.
Передзавантаження (prefetch) для списків: завантажувати наступні N зображень заздалегідь, поки користувач ще не доскролив до них. У RecyclerView — через RecyclerView.RecycledViewPool + DiffUtil. У UITableView — через prefetchDataSource (доступний з iOS 10).
Стандартні рішення та їхні підводні камені
Android: Glide та Coil — найпоширеніші бібліотеки. Glide при дефолтних налаштуваннях кешує у двох рівнях: memory cache (LruCache з розміром, похідним від доступної пам'яті) та disk cache (DiskLruCache). Coil написаний на Kotlin Coroutines і краще інтегрується з Compose через AsyncImage. Проблема виникає, коли розмір зображень у мережі не збігається з розміром ImageView: Glide за замовчуванням кешує вже трансформоване зображення (під конкретний розмір view), що призводить до промахів кешу при різних розмірах одного й того самого URL. Також часто зустрічається некоректна стратегія інвалідації: зображення оновлюються лише після перезапуску додатку, якщо не налаштований ETag або версію URL.
iOS: NSCache + ручна логіка або бібліотеки Kingfisher та SDWebImage. Kingfisher — де-факто стандарт для SwiftUI через .setImage(with:). Проблема, яку бачимо регулярно: кеш не враховує Cache-Control заголовки сервера, і застарілі зображення показуються користувачеві, поки TTL не закінчиться вручну. Крім того, дисковий кеш за замовчуванням зберігає зображення в директорії, яка може бути очищена при нестачі місця, що призводить до повторного завантаження.
React Native: react-native-fast-image поверх Glide/SDWebImage. Стандартний Image в RN не має нормального дискового кешу — картинки завантажуються заново при кожному монтуванні компонента, що помітно при навігації між екранами. Налаштування react-native-fast-image вимагає вказання розмірів та пріоритетів.
Flutter: Використовуйте пакет cached_network_image. Він надає CachedNetworkImageProvider з кешуванням на рівні пам'яті та диска, а також підтримку передзавантаження.
Чому важлива інвалідація кешу?
Без стратегії інвалідації користувачі бачать застарілі аватарки після зміни фото профілю. На практиці використовуємо два підходи: URL з версією (/avatar.jpg?v=42) та використання Cache-Control. Другий дозволяє скоротити трафік до 40%, оскільки сервер повертає 304 Not Modified, якщо контент не змінився. Також налаштовуємо Cache-Control з оптимальним max-age (наприклад, 86400 секунд для аватарок, 3600 для стрічки). Економія трафіку безпосередньо знижує витрати на передачу даних — для додатків із мільйоном користувачів це відчутно.
Що входить у роботу
При замовленні налаштування кешування зображень ми надаємо:
- Аналіз поточної архітектури та виявлення вузьких місць (аудит ~2 години)
- Вибір та налаштування бібліотеки з урахуванням вашої платформи (Android/iOS/React Native/Flutter)
- Реалізацію багаторівневого кешу (L1 + L2) з індивідуальними розмірами
- Налаштування prefetch для списків та інвалідацію через ETag/версію URL
- Документацію з експлуатації та рекомендації щодо подальшої підтримки
- Тестування під навантаженням (1000+ зображень) та виправлення помилок
Терміни — 2–4 робочих дні. Гарантуємо результат: кеш працюватиме коректно, без промахів та витоків пам'яті. Отримайте консультацію з налаштування кешу — ми оцінимо ваш проект і запропонуємо оптимальне рішення.
Процес роботи
- Аналітика: визначаємо профіль контенту (розміри, кількість, частота оновлення).
- Проектування: вибираємо бібліотеку, розміри кешу, стратегію інвалідації.
- Реалізація: впроваджуємо кеш, налаштовуємо placeholder та error-state, додаємо prefetch.
- Тестування: перевіряємо під навантаженням, відстежуємо пам'ять та дискове споживання.
- Деплой: інтеграція в CI/CD, документування.
Порівняння бібліотек
| Платформа | Бібліотека | L1 (пам'ять) | L2 (диск) | Prefetch | Інвалідація |
|---|---|---|---|---|---|
| Android | Glide | LruCache | DiskLruCache | Так | ETag, версія |
| Android | Coil | LruCache | DiskLruCache | Так | ETag, версія |
| iOS | Kingfisher | NSCache | FileManager | Так | ETag, Cache-Control |
| iOS | SDWebImage | NSCache | FileManager | Так | ETag |
| React Native | FastImage | (залежить від платформи) | - | - | ETag |
| Flutter | CachedNetworkImage | MemoryCache | DiskCache | Так | ETag, версія |
Рекомендовані розміри кешу за типом контенту
| Тип контенту | Memory cache (L1) | Disk cache (L2) |
|---|---|---|
| Аватарки (10-50 КБ) | 10-20 МБ | 50-100 МБ |
| Новинні зображення (200-500 КБ) | 20-30 МБ | 200-500 МБ |
| Галерея (1-5 МБ) | 30-50 МБ | 500-1000 МБ |
Наш досвід — 5+ років у мобільній розробці, понад 50 проектів з кешуванням зображень. Підтверджені кейси: зниження трафіку на 30-40% та прискорення скролу в 2 рази. Правильно налаштований кеш скорочує витрати на хмарне сховище до 30%.
Якщо ви зіткнулися з гальмуваннями через зображення — зв'яжіться з нами, оцінимо ваш проект і запропонуємо рішення під ключ.







