Coil هي مكتبة لتحميل الصور على Android، مكتوبة بلغة Kotlin ومبنية على coroutines. وفقاً للوثائق الرسمية، تدعم المكتبة Memory Cache و Disk Cache والتحويلات مع تسريع الأجهزة. تتميز Coil بحجم APK صغير (حوالي 150 كيلوبايت) والتوافق الكامل مع Jetpack Compose.
الخلاصة
Coil (Coroutine Image Loader) هي مكتبة لتحميل الصور على Android، مكتوبة بالكامل بلغة Kotlin وتستخدم coroutines للعمليات غير المتزامنة. توفر واجهة برمجة تطبيقات موحدة لتحميل الصور النقطية من الشبكة والموارد ونظام الملفات و Content Provider، مع تخزين مؤقت تلقائي متعدد المستويات.
على عكس Glide و Picasso، تستخدم Coil Kotlin Coroutines بدلاً من سلاسل الاسترجاعات، مما يجعل الكود أكثر خطية وقابلية للتنبؤ. يتم تنفيذ جميع عمليات التحميل وفك التشفير على خيوط خلفية من خلال dispatcher Dispatchers.IO، ويتم تسليم النتائج إلى الخيط الرئيسي دون تبديل صريح.
تدعم Coil التحويلات (Round و Blur و Grayscale) ورسوم الانتقال و SVG و GIF، بالإضافة إلى Targets المخصصة للعرض غير القياسي. وفقاً لـ Google I/O 2023، يُوصى باستخدام Coil في الدروس الرسمية لـ Jetpack Compose إلى جانب Glide.
ImageLoader هو المكون الرئيسي لـ Coil، المسؤول عن تنفيذ طلبات التحميل وإدارة التخزين المؤقت. يحتوي كل مثيل على مراجع لـ MemoryCache و DiskCache و BitmapPool ومجموعة coroutines. بشكل افتراضي، يُستخدم 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 إلى ImageLoader عبر enqueue أو execute. يقوم enqueue بتشغيل coroutine وإرجاع Disposable، مما يسمح بإلغاء التحميل عند مغادرة الشاشة. method execute هي وظيفة suspend تُرجع Result مباشرة.
يتحقق ImageLoader بالتسلسل من MemoryCache و DiskCache، وفقط عند عدم وجودهما ينفذ طلب شبكة عبر HttpEngine. بعد التحميل، يتم فك تشفير البايتات إلى Bitmap مع مراعاة الحجم المستهدف، وتطبيق التحويلات، وتخزين النتيجة في كلتا الذاكرة المؤقتة وتمريرها إلى Target.
تم بناء Coil على بنية مكونات مع إمكانية استبدال أي جزء عبر حقن التبعيات. يتم تسجيل جميع المكونات في ImageLoaderFactory وتمريرها إلى مُنشئ ImageLoader عبر builder.
ImageLoader هو نقطة الدخول لجميع عمليات التحميل. يحتوي كل مثيل على مجموعة coroutines و BitmapPool و MemoryCache و DiskCache وقائمة من المعترضين. بشكل افتراضي، يتم إنشاء مثيل عام واحد، ولكن للاختبارات الوحدوية يمكن إنشاء مثيلات منفصلة بذاكرة تخزين مؤقت معزولة.
MemoryCache هي ذاكرة تخزين مؤقت في الذاكرة تعتمد على LRU (الأقل استخداماً مؤخراً)، تخزن كائنات Bitmap المفكوكة. الحجم الأقصى الافتراضي هو 25% من الذاكرة المتاحة للتطبيق، ولكن لا يقل عن 32 ميجابايت. يتكون مفتاح التخزين المؤقت من URL + الحجم + التحويلات، مما يمنع استرجاع الصور القديمة.
DiskCache هي ذاكرة تخزين مؤقت قائمة على الملفات للبيانات الخام (JPEG و PNG و WebP) والبيانات الوصفية المفكوكة. توجد في دليل التخزين المؤقت للتطبيق وتدعم التنظيف التلقائي عند تجاوز الحد. تتم عمليات القرص عبر DiskCache.Builder مع إعدادات الدليل والحجم الأقصى.
تنفذ Coil استراتيجية تخزين مؤقت متعددة المستويات تقلل من طلبات الشبكة وتسريع عرض الصور. كل مستوى له غرضه وعمر البيانات الخاص به.
| المستوى | نوع التخزين | عمر البيانات | الحجم الافتراضي |
|---|---|---|---|
| Memory Cache | Bitmap في الذاكرة | حتى الإزالة LRU | 25% من heap، من 32 ميجابايت |
| Disk Cache | ملفات JPEG/WebP | حتى تجاوز الحد | 250 ميجابايت |
| Http Cache | استجابات OkHttp | حسب رؤوس Cache-Control | يعتمد على عميل HTTP |
يوفر Memory Cache وصولاً فورياً إلى Bitmaps المفكوكة بالفعل. يضمن 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، مع جميع المعلمات الاختيارية من خلال مُهيئ lambda.
imageView.load("https://example.com/photo.jpg") {
crossfade(true)
placeholder(R.drawable.placeholder)
error(R.drawable.error)
size(300, 300)
transformations(CircleCropTransformation())
}
تُرجع method load Disposable، يمكن إلغاؤه في onDestroy أو عند إعادة استخدام View. يمنع ذلك تسرب الذاكرة وطلبات الشبكة غير الضرورية أثناء التمرير السريع للقائمة.
AsyncImage هي دالة composable لتحميل الصور في واجهة المستخدم التصريحية. تقبل أي مصدر بيانات وثلاث معاملات اختيارية للحالات: placeholder و error و success.
@Composable
fun NetworkImage(url: String) {
AsyncImage(
model = url,
contentDescription = "صورة الشبكة",
placeholder = ColorPainter(Color.Gray),
error = ColorPainter(Color.Red)
)
}
SubcomposeAsyncImage هي نسخة أكثر مرونة تسمح بتخصيص العرض أثناء التحميل من خلال فتحة المحتوى. هذا مفيد للهياكل العظمية (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 كيلوبايت | ~500 كيلوبايت | ~120 كيلوبايت |
| Coroutines | مضمنة | لا (استرجاعات) | لا (استرجاعات) |
| Jetpack Compose | دعم أصلي | عبر accompanist | جهة خارجية |
| GIF/WebP | نعم (مضمن) | نعم (مضمن) | لا |
| توصية Google | نعم (I/O 2023) | نعم | لا |
للمشاريع الجديدة على Kotlin و Jetpack Compose، يصبح Coil الخيار الطبيعي بفضل عدم وجود تبعيات إضافية للـ coroutines والحجم الصغير. يبقى 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 — 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 باستخدام coroutines. تُستخدم للتحميل غير المتزامن والتخزين المؤقت وعرض الصور النقطية من الشبكة أو الموارد أو نظام الملفات.
Coil مكتوب 100% بلغة Kotlin ويستخدم coroutines بدلاً من آلية الاسترجاعات في Glide. Coil له حجم APK أصغر (~150 كيلوبايت مقابل ~500 كيلوبايت) ودعم أصلي لـ 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. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا