Coil — це бібліотека для завантаження зображень на Android, написана на Kotlin і побудована на базі корутин. За даними офіційної документації, бібліотека підтримує Memory Cache, Disk Cache та трансформації з апаратним прискоренням. Coil вирізняється мінімальним розміром APK (близько 150 KB) і повною сумісністю з Jetpack Compose.
Головне
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.
ImageLoader — основний компонент Coil, відповідальний за виконання запитів завантаження та управління кешем. Кожен екземпляр містить посилання на MemoryCache, DiskCache, BitmapPool та пул корутин. За замовчуванням використовується синглтон, створюваний через Coil.imageLoader(context).
ImageRequest — об'єкт, що описує один запит на завантаження зображення: джерело даних (URL, URI, Int ресурс), цільовий ImageView або Target, трансформації, налаштування кешування та placeholder. ImageRequest збирається через builder, що забезпечує гнучкість та читабельність.
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.
Coil побудований на компонентній архітектурі з можливістю заміни будь-якої частини через Dependency Injection. Всі компоненти реєструються в ImageLoaderFactory і передаються в конструктор ImageLoader через builder.
ImageLoader — точка входу для всіх операцій завантаження. Кожен інстанс містить пул корутин, BitmapPool, MemoryCache, DiskCache та список перехоплювачів. За замовчуванням створюється один глобальний інстанс, але для модульного тестування можна створювати окремі екземпляри з ізольованим кешем.
MemoryCache — in-memory кеш на основі LRU (Least Recently Used), що зберігає декодовані Bitmap-об'єкти. Максимальний розмір за замовчуванням — 25% доступної пам'яті додатку, але не менше 32 MB. Ключ кеша формується з URL + розміру + трансформацій, що виключає видачу неактуального зображення.
DiskCache — файловий кеш для сирих даних (JPEG, PNG, WebP) та декодованих метаданих. Розміщується в кеш-директорії додатку і підтримує автоматичне очищення при перевищенні ліміту. Робота з диском виконується через DiskCache.Builder з налаштуванням директорії та максимального розміру.
Coil реалізує багаторівневу стратегію кешування, що мінімізує мережеві запити та прискорює відображення зображень. Кожен рівень має свою мету та час життя даних.
| Рівень | Тип зберігання | Час життя | Розмір за замовчуванням |
|---|---|---|---|
| Memory Cache | Bitmap в пам'яті | До витіснення LRU | 25% 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 надає кілька способів інтеграції залежно від архітектури додатку. Розглянемо три ключові сценарії з робочими прикладами коду.
load — extension-функція для ImageView, найпростіший спосіб завантажити зображення одним рядком. Функція приймає URL, URI, Int-ресурс або File та всі опціональні параметри через лямбда-конфігуратор.
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. Це запобігає витокам пам'яті та зайвим мережевим запитам при швидкому скролі списку.
AsyncImage — composable-функція для завантаження зображень в декларативному UI. Приймає будь-яке джерело даних та три опціональних параметри для станів: placeholder, error та success.
@Composable
fun NetworkImage(url: String) {
AsyncImage(
model = url,
contentDescription = "мережеве зображення",
placeholder = ColorPainter(Color.Gray),
error = ColorPainter(Color.Red)
)
}
SubcomposeAsyncImage — більш гнучка версія, що дозволяє кастомізувати відображення під час завантаження через content-слот. Це корисно для скелетонів (shimmer) та прогрес-барів.
Якщо ImageView або AsyncImage не підходять, можна реалізувати Target з єдиним методом onSuccess, що приймає Bitmap. Це використовується для завантаження в Notification, RemoteViews або OpenGL текстуру.
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 конкурує з Glide та Picasso, кожна з яких має сильні сторони. Порівняння основних характеристик представлено в таблиці.
| Характеристика | Coil | Glide | Picasso |
|---|---|---|---|
| Мова | Kotlin (100%) | Java + Kotlin | Java |
| Розмір 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 виконується через Gradle-залежність. Після додавання бібліотека автоматично реєструє ImageLoader через ContentProvider, тому ручна ініціалізація в Application не потрібна. При необхідності кастомізації створюється власний ImageLoader через builder.
// 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 з готовим пулом з'єднань.
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 — бібліотека для завантаження зображень на Android, написана на Kotlin з використанням корутин. Вона використовується для асинхронного завантаження, кешування та відображення растрових зображень з мережі, ресурсів або файлової системи.
Coil написаний на 100% Kotlin і використовує корутини замість callback-механізму в Glide. Coil має менший розмір APK (~150 KB проти ~500 KB) та нативну підтримку Jetpack Compose через AsyncImage.
Додайте залежність io.coil-kt:coil:2.6.0 в build.gradle.kts. Для Jetpack Compose також додайте io.coil-kt:coil-compose:2.6.0. Бібліотека автоматично реєструє ImageLoader через ContentProvider.
Coil підтримує JPEG, PNG, WebP, BMP, SVG (через модуль coil-svg) та GIF (через модуль coil-gif). Формати AVIF та HEIF підтримуються через кастомний декодер на пристроях з Android 10+.
Кеш налаштовується через ImageLoader.Builder: memoryCache із зазначенням відсотка від heap, diskCache з шляхом та лімітом в байтах. Політики кеша (ENABLED, DISABLED, READ_ONLY) налаштовуються пер-запит через CachePolicy.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також