Ми стикаємося з цією проблемою на кожному другому проєкті: додаток завантажує зображення одне за одним, а пам'ять зростає до OOM. Або — більш м'який сценарій — користувачі на iPhone 12 у режимі Low Data Mode чекають 4–6 секунд до появи першого зображення, тому що завантажується оригінал 4K замість прев'ю. З нашої практики: замовник звернувся зі скаргою на вильоти під час перегляду галереї з 200 фото. Android Profiler показував Bitmap allocation 4, 8, 14, 23 MB… Типовий корінь — відсутність параметризованих URL резайзу та неправильний кеш. Ми впроваджуємо зв'язку: CDN-резайз + disk-кеш + BlurHash. Оптимізація завантаження зображень мобільного додатка потребує комплексного підходу.
Які проблеми вирішує оптимізація завантаження зображень?
Неправильний розмір зображення
Сервер віддає оригінал 2400×3200, ImageView — 80×80 dp. Glide, Kingfisher або Coil роблять downsampling, але спочатку ці 29 MB приходять по мережі та декодуються в пам'яті. Параметризовані URL резайзу (?w=160&h=160&fit=crop) вирішують проблему до завантаження. Це знижує трафік на 30-50% і прискорює відображення.
Відсутність disk-кешу
За замовчуванням SDWebImage кешує на диск, але якщо хтось встановив SDWebImageOptions.refreshCached для «свіжості» даних — кожен запуск додатка завантажує всі зображення заново. На екранах з аватарами користувачів це означає 20–30 зайвих мережевих запитів при кожному відкритті. Правильний ліміт кешу (500 MB) дозволяє завантажувати зображення один раз.
Послідовне завантаження замість паралельного
Кастомні реалізації через URLSession.dataTask нерідко створюють чергу, де наступний запит стартує після завершення попереднього. У списку з 10 елементів — чекаємо сумарно всі 10 RTT замість максимального з них.
OOM при завантаженні галереї
Пагінація з вікном видимості ±2 сторінки, параметризовані URL з розміром під ImageView та обмеження кешу decoded images до 20–100 MB вирішують проблему. У carousel з 50+ зображеннями — lazy loading та передзавантаження тільки поточної та сусідніх.
Чому важлива оптимізація завантаження зображень?
Оптимізація завантаження зображень безпосередньо впливає на користувацький досвід та метрики додатка. Повільне завантаження — причина до 40% відмов на мобільних пристроях. Впровадження методів, описаних вище, окупається за рахунок зниження витрат на CDN та підвищення утримання користувачів. В одному з проєктів ми скоротили час завантаження з 8 до 1.2 секунди, що призвело до збільшення конверсії на 15%.
Чому важливо використовувати WebP?
WebP забезпечує стиснення на 25–35% краще JPEG при тій самій візуальній якості. На Android Glide підтримує WebP з коробки, на iOS Kingfisher — через встановлення прапора .webpConversion. Для максимальної ефективності передавайте параметр формату в URL — ?format=webp. Це зменшує трафік і прискорює завантаження, заощаджуючи бюджет на хостинг зображень.
Як ми оптимізуємо завантаження зображень?
Наш підхід до оптимізації завантаження зображень включає стек: на iOS — Kingfisher для Swift-проєктів, SDWebImage для Obj-C legacy. Kingfisher зручний KFImage в SwiftUI та нативною підтримкою @MainActor. Ключові налаштування:
KingfisherManager.shared.cache.diskStorage.config.sizeLimit = 500 * 1024 * 1024 // 500 MB KingfisherManager.shared.cache.memoryStorage.config.totalCostLimit = 100 * 1024 * 1024 // 100 MB Для прогресивного завантаження JPEG — ImageDataProcessor з ProgressiveJPEGAddon. Користувач бачить розмите зображення одразу, а не плейсхолдер 2 секунди.
На Android: Coil для Compose-проєктів (нативна AsyncImage), Glide для View-based. Glide вміє thumbnail(0.1f) — завантажує 10% від оригінального розміру як placeholder поки грузиться повна версія. Для WebP-конвертації на сервері Glide справляється з коробки, Coil вимагає SvgDecoder / VideoFrameDecoder через окремі залежності.
Обов'язковий паттерн для обох платформ: параметризовані URL з розміром під конкретний ImageView. Якщо бекенд на Cloudinary або imgproxy — передаємо ?width={viewWidthDp * density}&format=webp&quality=80.
Placeholder стратегія
Пустий сірий прямокутник — погано. BlurHash або ThumbHash — добре. Це компактний (20–30 байт) хеш зображення, який рендериться локально у вигляді кольорового розмитого прев'ю до завантаження реального контенту. На iOS — бібліотека BlurHash, на Android — io.github.nicklockwood:thumbhash. Дані хешу приходять разом з JSON-відповіддю API — нульові мережеві витрати на прев'ю.
Кейс: carousel з 50 зображеннями (з нашої практики)
Клієнт реалізував UIScrollView з UIImageView через page control. При відкритті екрану — одразу завантажував всі 50 зображень. На повільному 3G WKWebView закривався по OOM через 3–4 листання.
Рішення: lazy loading через UIPageViewController з вікном видимості ±2 сторінки. NSCache з лімітом 20 MB для decoded images. Решта — тільки URL в пам'яті. Час до першої взаємодії скоротився з 8 до 1.2 секунди, а витрати на CDN зменшилися на 40%.
Порівняння підходів
| Метод | Економія трафіку | Час завантаження | Складність впровадження |
|---|---|---|---|
| Ресайз на сервері | 30–50% | -1.5 с | Низька (змінити URL) |
| BlurHash | 0% (хеш) | На 1.5 с швидше | Середня (додати хеш) |
| Disk-кеш 500 MB | До 80% при повторах | -0.7 с | Низька (налаштування ліміту) |
| Прогресивний JPEG | 0% | -0.3 с на прев'ю | Середня (додати процесор) |
| Типова помилка | Наслідок | Виправлення |
|---|---|---|
| Завантаження оригіналу без ресайзу | OOM, 4-6 с завантаження | Параметризований URL |
| Відсутність disk-кешу | Багаторазові запити | Налаштування ліміту кешу |
| Послідовне завантаження | Сумарне очікування | Паралельне завантаження |
Налаштування параметризованих URL
Для imgproxy використовуйте формат: /rs:fit:320:320/plain/https://example.com/image.jpg. Cloudinary: /c_fit,w_320,h_320/f_webp,q_80. Параметри повинні враховувати щільність екрану (density).
Що входить в роботу
- Аудит поточної схеми завантаження зображень (мережева бібліотека, кеш, розміри)
- Інтеграція Kingfisher/Glide/Coil з оптимальними налаштуваннями
- Налаштування параметризованих URL ресайзу (CDN)
- Впровадження BlurHash або ThumbHash прев'ю
- Оптимізація пагінації та lazy loading
- Тестування на реальних пристроях та в умовах поганого з'єднання
- Документація з архітектури та рекомендації для підтримки
Терміни
Аудит завантаження зображень та налаштування бібліотеки — 1–3 дні. Якщо потрібна інтеграція CDN-резайзу та BlurHash по всьому додатку — 1 тиждень. Вартість розраховується індивідуально.
Гарантуємо, що після оптимізації OOM не повториться, а час завантаження скоротиться щонайменше вдвічі. Наш досвід — понад 5 років роботи з мобільними додатками, понад 50 успішних проєктів. Отримайте консультацію — ми відповімо на запитання та запропонуємо план покращень. Замовте аудит або зв'яжіться з нами, щоб почати оптимізацію.







