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 و استخر کوروتینها است. به طور پیشفرض از Singleton ایجاد شده از طریق 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 از طریق enqueue یا execute به ImageLoader منتقل میشود. متد enqueue یک کوروتین را راهاندازی میکند و Disposable برمیگرداند که امکان لغو بارگذاری در هنگام خروج از صفحه را فراهم میکند. متد execute یک تابع suspend است که مستقیماً Result برمیگرداند.
ImageLoader به ترتیب MemoryCache، DiskCache را بررسی میکند و فقط در صورت عدم وجود در هر دو، درخواست شبکه را از طریق HttpEngine انجام میدهد. پس از بارگذاری، بایتها با در نظر گرفتن اندازه هدف به Bitmap رمزگشایی میشوند، تبدیلها اعمال میشوند، نتیجه در هر دو حافظه پنهان ذخیره میشود و به Target منتقل میشود.
Coil بر روی معماری مؤلفهای با امکان تعویض هر بخش از طریق Dependency Injection ساخته شده است. تمام مؤلفهها در ImageLoaderFactory ثبت میشوند و از طریق Builder به سازنده ImageLoader منتقل میشوند.
ImageLoader — نقطه ورود برای تمام عملیات بارگذاری است. هر نمونه شامل استخر کوروتینها، BitmapPool، MemoryCache، DiskCache و لیست interceptors است. به طور پیشفرض یک نمونه سراسری ایجاد میشود، اما برای تست ماژولار میتوان نمونههای جداگانه با حافظه پنهان ایزوله ایجاد کرد.
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 — تابع 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 — نسخه انعطافپذیرتر که امکان سفارشیسازی نمایش در حین بارگذاری را از طریق slot content فراهم میکند. این برای skeleton (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 استفاده میشود — Singleton ایجاد شده در 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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید