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 собирается через билдер, что обеспечивает гибкость и читаемость.
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 через билдер.
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 | Нативная поддержка | Через аккомпанимент | Сторонняя |
| GIF/WebP | Да (встроено) | Да (встроено) | Нет |
| Рекомендация Google | Да (I/O 2023) | Да | Нет |
Для новых проектов на Kotlin и Jetpack Compose Coil становится естественным выбором благодаря нулевой дополнительной зависимости от корутин и минимальному размеру. Glide остаётся предпочтительным для сложных сценариев с анимациями и видео-превью. Picasso уступает обеим по функциональности, но выигрывает в простоте.
Подключение Coil в проект Android выполняется через Gradle-зависимость. После добавления библиотека автоматически регистрирует ImageLoader через ContentProvider, поэтому ручная инициализация в Application не требуется. При необходимости кастомизации создаётся собственный ImageLoader через билдер.
// 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также