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.
Coil е изграден върху компонентна архитектура с възможност за замяна на всяка част чрез Dependency Injection. Всички компоненти се регистрират в ImageLoaderFactory и се предават в конструктора на ImageLoader чрез builder.
ImageLoader — входна точка за всички операции по зареждане. Всеки екземпляр съдържа пул от корутини, BitmapPool, MemoryCache, DiskCache и списък от интерсептори. По подразбиране се създава един глобален екземпляр, но за модулно тестване могат да се създават отделни екземпляри с изолиран кеш.
MemoryCache — кеш в паметта, базиран на 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 осигурява моментален достъп до вече декодирани битмапове. 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 — функция-разширение за 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 | Естествена поддръжка | Чрез Accompaniment | Трета страна |
| GIF/WebP | Да (вградено) | Да (вградено) | Не |
| Препоръка от Google | Да (I/O 2023) | Да | Не |
За нови проекти на Kotlin и Jetpack Compose Coil се превръща в естествен избор благодарение на нулевата допълнителна зависимост от корутини и минималния размер. Glide остава предпочитан за сложни сценарии с анимации и видео прегледи. Picasso отстъпва и на двете по функционалност, но печели по простота.
Свързването на Coil с Android проект се извършва чрез Gradle зависимост. След добавяне библиотеката автоматично регистрира ImageLoader чрез ContentProvider, така че ръчна инициализация в Application не е необходима. При нужда от персонализиране се създава собствен ImageLoader чрез builder.
// build.gradle.kts (модул на приложението)
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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също