Coil — що це, ключові поняття та ImageLoader в Android

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

Coil — це бібліотека для завантаження зображень на Android, написана на Kotlin і побудована на базі корутин. За даними офіційної документації, бібліотека підтримує Memory Cache, Disk Cache та трансформації з апаратним прискоренням. Coil вирізняється мінімальним розміром APK (близько 150 KB) і повною сумісністю з Jetpack Compose.

Головне

  • Coil — бібліотека для завантаження зображень на Android, яка використовує Kotlin Coroutines та Kotlin Serialization.
  • ImageLoader — центральний компонент, що керує запитами, кешуванням та трансформаціями зображень.
  • Memory Cache зберігає декодовані растрові зображення в оперативній пам'яті для миттєвого доступу.
  • Disk Cache зберігає стиснені файли на накопичувачі для автономної роботи та зниження трафіку.
  • Jetpack Compose — бібліотека підтримує AsyncImage та SubcomposeAsyncImage для декларативного UI.

Що таке Coil?

Coil (Coroutine Image Loader) — це бібліотека для завантаження зображень на Android, повністю написана на Kotlin і яка використовує корутини для асинхронної роботи. Вона надає єдиний API для завантаження растрових зображень з мережі, ресурсів, файлової системи та Content Provider, з автоматичним кешуванням на кількох рівнях.

На відміну від Glide та Picasso, Coil використовує Kotlin Coroutines замість ланцюжків callback, що робить код більш лінійним та передбачуваним. Всі операції завантаження та декодування виконуються на фонових потоках через диспетчер Dispatchers.IO, а результат доставляється в головний потік без явного перемикання.

Coil підтримує трансформації (Round, Blur, Grayscale), анімацію переходів, SVG та GIF, а також кастомні Target для нестандартного відображення. За даними Google I/O 2023, Coil рекомендований в офіційних туторіалах по Jetpack Compose нарівні з Glide.

  • Розмір APK — близько 150 KB (проти 500 KB у Glide)
  • Мінімальна версія Android — API 21 (Lollipop)
  • Залежність — Kotlin Coroutines (вбудована)

Як працює Coil: ImageLoader та ImageRequest

ImageLoader — основний компонент Coil, відповідальний за виконання запитів завантаження та управління кешем. Кожен екземпляр містить посилання на MemoryCache, DiskCache, BitmapPool та пул корутин. За замовчуванням використовується синглтон, створюваний через Coil.imageLoader(context).

ImageRequest

ImageRequest — об'єкт, що описує один запит на завантаження зображення: джерело даних (URL, URI, Int ресурс), цільовий ImageView або Target, трансформації, налаштування кешування та placeholder. ImageRequest збирається через builder, що забезпечує гнучкість та читабельність.

kotlin
val request = ImageRequest.Builder(context)
    .data("https://example.com/image.jpg")
    .crossfade(true)
    .size(512, 512)
    .transformations(listOf(RoundedCornersTransformation(12f)))
    .memoryCachePolicy(CachePolicy.ENABLED)
    .diskCachePolicy(CachePolicy.ENABLED)
    .target(imageView)
    .build()

Після збірки ImageRequest передається в ImageLoader через enqueue або execute. Метод enqueue запускає корутину і повертає Disposable, що дозволяє скасувати завантаження при виході з екрану. Метод execute — suspend-функція, що повертає Result безпосередньо.

Потік виконання запиту

ImageLoader послідовно перевіряє MemoryCache, DiskCache і тільки при промаху обох виконує мережевий запит через HttpEngine. Після завантаження байти декодуються в Bitmap з урахуванням target size, застосовуються трансформації, результат зберігається в обидва кеші та передається в Target.

  • Memory Cache — перевірка в першу чергу, ключ — URL + параметри
  • Disk Cache — перевірка при відсутності в пам'яті, ключ — MD5 URL
  • HttpEngine — за замовчуванням OkHttp, кастомізований через компонент

Основні компоненти Coil

Coil побудований на компонентній архітектурі з можливістю заміни будь-якої частини через Dependency Injection. Всі компоненти реєструються в ImageLoaderFactory і передаються в конструктор ImageLoader через builder.

ImageLoader

ImageLoader — точка входу для всіх операцій завантаження. Кожен інстанс містить пул корутин, BitmapPool, MemoryCache, DiskCache та список перехоплювачів. За замовчуванням створюється один глобальний інстанс, але для модульного тестування можна створювати окремі екземпляри з ізольованим кешем.

MemoryCache

MemoryCache — in-memory кеш на основі LRU (Least Recently Used), що зберігає декодовані Bitmap-об'єкти. Максимальний розмір за замовчуванням — 25% доступної пам'яті додатку, але не менше 32 MB. Ключ кеша формується з URL + розміру + трансформацій, що виключає видачу неактуального зображення.

DiskCache

DiskCache — файловий кеш для сирих даних (JPEG, PNG, WebP) та декодованих метаданих. Розміщується в кеш-директорії додатку і підтримує автоматичне очищення при перевищенні ліміту. Робота з диском виконується через DiskCache.Builder з налаштуванням директорії та максимального розміру.

Рівні кешування в Coil

Coil реалізує багаторівневу стратегію кешування, що мінімізує мережеві запити та прискорює відображення зображень. Кожен рівень має свою мету та час життя даних.

РівеньТип зберіганняЧас життяРозмір за замовчуванням
Memory CacheBitmap в пам'ятіДо витіснення LRU25% heap, від 32 MB
Disk CacheФайли JPEG/WebPДо перевищення ліміту250 MB
Http CacheВідповіді OkHttpЗа заголовками Cache-ControlЗалежить від HTTP-клієнта

Memory Cache забезпечує миттєвий доступ до вже декодованих Bitmap. Disk Cache гарантує роботу додатку без мережі (offline-first) після першого завантаження. Http Cache на рівні OkHttp обробляє умовні запити ETag та If-Modified-Since.

Політики кешування налаштовуються пер-запит через CachePolicy з трьома значеннями: ENABLED, READ_ONLY, WRITE_ONLY, DISABLED. Наприклад, для аватарів користувачів можна встановити READ_ONLY для Memory Cache та ENABLED для Disk Cache.

Приклади використання Coil на Kotlin

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

Завантаження в ImageView через розширення

load — extension-функція для ImageView, найпростіший спосіб завантажити зображення одним рядком. Функція приймає URL, URI, Int-ресурс або File та всі опціональні параметри через лямбда-конфігуратор.

kotlin
imageView.load("https://example.com/photo.jpg") {
    crossfade(true)
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    size(300, 300)
    transformations(CircleCropTransformation())
}

Метод load повертає Disposable, який можна скасувати в onDestroy або при перевикористанні View. Це запобігає витокам пам'яті та зайвим мережевим запитам при швидкому скролі списку.

Використання в Jetpack Compose

AsyncImage — composable-функція для завантаження зображень в декларативному UI. Приймає будь-яке джерело даних та три опціональних параметри для станів: placeholder, error та success.

kotlin
@Composable
fun NetworkImage(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "мережеве зображення",
        placeholder = ColorPainter(Color.Gray),
        error = ColorPainter(Color.Red)
    )
}

SubcomposeAsyncImage — більш гнучка версія, що дозволяє кастомізувати відображення під час завантаження через content-слот. Це корисно для скелетонів (shimmer) та прогрес-барів.

Кастомний Target для нестандартного виведення

Якщо ImageView або AsyncImage не підходять, можна реалізувати Target з єдиним методом onSuccess, що приймає Bitmap. Це використовується для завантаження в Notification, RemoteViews або OpenGL текстуру.

kotlin
val target = object : BitmapTarget() {
    override fun onSuccess(result: Bitmap) {
        notificationRemoteView.setImageViewBitmap(R.id.icon, result)
    }
}

imageLoader.enqueue(
    ImageRequest.Builder(context)
        .data(url)
        .target(target)
        .build()
)

Порівняння Coil з іншими бібліотеками

Вибір бібліотеки для завантаження зображень залежить від вимог проекту. Coil конкурує з Glide та Picasso, кожна з яких має сильні сторони. Порівняння основних характеристик представлено в таблиці.

ХарактеристикаCoilGlidePicasso
МоваKotlin (100%)Java + KotlinJava
Розмір APK~150 KB~500 KB~120 KB
КорутиниВбудованіНі (callback)Ні (callback)
Jetpack ComposeНативна підтримкаЧерез accompanistСтороння
GIF/WebPТак (вбудовано)Так (вбудовано)Ні
Рекомендація GoogleТак (I/O 2023)ТакНі

Для нових проектів на Kotlin та Jetpack Compose Coil стає природним вибором завдяки нульовій додатковій залежності від корутин та мінімальному розміру. Glide залишається кращим для складних сценаріїв з анімаціями та відео-прев'ю. Picasso поступається обом за функціональністю, але виграє в простоті.

Налаштування Coil в проекті Android

Підключення Coil в проект Android виконується через Gradle-залежність. Після додавання бібліотека автоматично реєструє ImageLoader через ContentProvider, тому ручна ініціалізація в Application не потрібна. При необхідності кастомізації створюється власний ImageLoader через builder.

kotlin
// build.gradle.kts (app module)
dependencies {
    implementation("io.coil-kt:coil:2.6.0")
    // Для Jetpack Compose додатково:
    implementation("io.coil-kt:coil-compose:2.6.0")
    // Для SVG підтримки:
    implementation("io.coil-kt:coil-svg:2.6.0")
    // Для GIF підтримки:
    implementation("io.coil-kt:coil-gif:2.6.0")
}

Для кастомізації ImageLoader використовується ImageLoaderFactory — синглтон, створюваний в Application.onCreate. У фабриці можна налаштувати ліміти кеша, HTTP-клієнт, кастомні декодери та логування. За замовчуванням Coil використовує OkHttp з готовим пулом з'єднань.

kotlin
class App : Application(), ImageLoaderFactory {
    override fun newImageLoader(): ImageLoader {
        return ImageLoader.Builder(this)
            .memoryCache {
                MemoryCache.Builder()
                    .maxSizePercent(0.25)
                    .build()
            }
            .diskCache {
                DiskCache.Builder()
                    .directory(cacheDir.resolve("coil_cache"))
                    .maxSizeBytes(512 * 1024 * 1024)
                    .build()
            }
            .build()
    }
}

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

Що таке Coil і для чого він використовується?

Coil — бібліотека для завантаження зображень на Android, написана на Kotlin з використанням корутин. Вона використовується для асинхронного завантаження, кешування та відображення растрових зображень з мережі, ресурсів або файлової системи.

Чим Coil відрізняється від Glide?

Coil написаний на 100% Kotlin і використовує корутини замість callback-механізму в Glide. Coil має менший розмір APK (~150 KB проти ~500 KB) та нативну підтримку Jetpack Compose через AsyncImage.

Як підключити Coil до проекту на Kotlin?

Додайте залежність io.coil-kt:coil:2.6.0 в build.gradle.kts. Для Jetpack Compose також додайте io.coil-kt:coil-compose:2.6.0. Бібліотека автоматично реєструє ImageLoader через ContentProvider.

Які типи зображень підтримує Coil?

Coil підтримує JPEG, PNG, WebP, BMP, SVG (через модуль coil-svg) та GIF (через модуль coil-gif). Формати AVIF та HEIF підтримуються через кастомний декодер на пристроях з Android 10+.

Як налаштувати кеш в Coil?

Кеш налаштовується через ImageLoader.Builder: memoryCache із зазначенням відсотка від heap, diskCache з шляхом та лімітом в байтах. Політики кеша (ENABLED, DISABLED, READ_ONLY) налаштовуються пер-запит через CachePolicy.

Підсумки

  • Coil — бібліотека завантаження зображень на Kotlin з повною підтримкою корутин та Jetpack Compose.
  • ImageLoader керує запитами, кешуванням та трансформаціями, використовуючи два рівні кеша: Memory Cache та Disk Cache.
  • AsyncImage та SubcomposeAsyncImage надають інтеграцію з Compose, підтримуючи placeholder, error та success-стани.
  • Розмір APK ~150 KB робить Coil однією з найкомпактніших бібліотек завантаження зображень на ринку.
  • Трансформації (RoundedCorners, CircleCrop, Blur) вбудовані в бібліотеку і працюють з апаратним прискоренням.
  • Disk Cache забезпечує офлайн-доступ до раніше завантажених зображень з налаштовуваним лімітом зберігання.
  • Coil рекомендований Google в офіційних посібниках по Jetpack Compose, що підтверджує його статус сучасного стандарту.

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

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

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

Читайте також