Coil — ما هو، المفاهيم الأساسية و ImageLoader في Android

المؤلف: IT Sectr نُشر: 2026-05-05 وقت القراءة: 9 دق

Coil هي مكتبة لتحميل الصور على Android، مكتوبة بلغة Kotlin ومبنية على coroutines. وفقاً للوثائق الرسمية، تدعم المكتبة Memory Cache و Disk Cache والتحويلات مع تسريع الأجهزة. تتميز Coil بحجم APK صغير (حوالي 150 كيلوبايت) والتوافق الكامل مع Jetpack Compose.

الخلاصة

  • Coil هي مكتبة لتحميل الصور على Android تستخدم Kotlin Coroutines و Kotlin Serialization.
  • ImageLoader هو المكون المركزي الذي يدير الطلبات والتخزين المؤقت وتحويلات الصور.
  • Memory Cache يخزن الصور النقطية المفكوكة في الذاكرة العشوائية للوصول الفوري.
  • Disk Cache يحفظ الملفات المضغوطة على وحدة التخزين للعمل دون اتصال وتقليل حركة المرور.
  • Jetpack Compose — تدعم المكتبة AsyncImage و SubcomposeAsyncImage لواجهة المستخدم التصريحية.

ما هو Coil؟

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.

  • حجم APK — حوالي 150 كيلوبايت (مقابل 500 كيلوبايت لـ Glide)
  • الحد الأدنى لإصدار Android — API 21 (Lollipop)
  • التبعية — Kotlin Coroutines (مضمنة)

كيف يعمل Coil: ImageLoader و ImageRequest

ImageLoader هو المكون الرئيسي لـ Coil، المسؤول عن تنفيذ طلبات التحميل وإدارة التخزين المؤقت. يحتوي كل مثيل على مراجع لـ MemoryCache و DiskCache و BitmapPool ومجموعة coroutines. بشكل افتراضي، يُستخدم singleton يتم إنشاؤه عبر Coil.imageLoader(context).

ImageRequest

ImageRequest هو كائن يصف طلب تحميل صورة واحد: مصدر البيانات (URL أو URI أو مورد Int) و ImageView أو Target الهدف والتحويلات وإعدادات التخزين المؤقت والplaceholder. يتم بناء ImageRequest من خلال builder، مما يضمن المرونة والوضوح.

kotlin
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.

  • Memory Cache — يتم التحقق أولاً، المفتاح هو URL + المعلمات
  • Disk Cache — يتم التحقق عند عدم وجودها في الذاكرة، المفتاح هو MD5 للـ URL
  • HttpEngine — OkHttp افتراضياً، قابل للتخصيص عبر المكون

المكونات الأساسية لـ Coil

تم بناء Coil على بنية مكونات مع إمكانية استبدال أي جزء عبر حقن التبعيات. يتم تسجيل جميع المكونات في ImageLoaderFactory وتمريرها إلى مُنشئ ImageLoader عبر builder.

ImageLoader

ImageLoader هو نقطة الدخول لجميع عمليات التحميل. يحتوي كل مثيل على مجموعة coroutines و BitmapPool و MemoryCache و DiskCache وقائمة من المعترضين. بشكل افتراضي، يتم إنشاء مثيل عام واحد، ولكن للاختبارات الوحدوية يمكن إنشاء مثيلات منفصلة بذاكرة تخزين مؤقت معزولة.

MemoryCache

MemoryCache هي ذاكرة تخزين مؤقت في الذاكرة تعتمد على LRU (الأقل استخداماً مؤخراً)، تخزن كائنات Bitmap المفكوكة. الحجم الأقصى الافتراضي هو 25% من الذاكرة المتاحة للتطبيق، ولكن لا يقل عن 32 ميجابايت. يتكون مفتاح التخزين المؤقت من URL + الحجم + التحويلات، مما يمنع استرجاع الصور القديمة.

DiskCache

DiskCache هي ذاكرة تخزين مؤقت قائمة على الملفات للبيانات الخام (JPEG و PNG و WebP) والبيانات الوصفية المفكوكة. توجد في دليل التخزين المؤقت للتطبيق وتدعم التنظيف التلقائي عند تجاوز الحد. تتم عمليات القرص عبر DiskCache.Builder مع إعدادات الدليل والحجم الأقصى.

مستويات التخزين المؤقت في Coil

تنفذ Coil استراتيجية تخزين مؤقت متعددة المستويات تقلل من طلبات الشبكة وتسريع عرض الصور. كل مستوى له غرضه وعمر البيانات الخاص به.

المستوىنوع التخزينعمر البياناتالحجم الافتراضي
Memory CacheBitmap في الذاكرةحتى الإزالة LRU25% من 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 في Kotlin

توفر Coil عدة طرق للتكامل حسب بنية التطبيق. دعنا نستعرض ثلاثة سيناريوهات رئيسية مع أمثلة أكواد عملية.

التحميل في ImageView عبر الامتداد

load هي دالة امتداد لـ ImageView، أبسط طريقة لتحميل صورة بسطر واحد. تقبل الدالة URL أو URI أو مورد Int أو File، مع جميع المعلمات الاختيارية من خلال مُهيئ lambda.

kotlin
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. يمنع ذلك تسرب الذاكرة وطلبات الشبكة غير الضرورية أثناء التمرير السريع للقائمة.

الاستخدام في Jetpack Compose

AsyncImage هي دالة composable لتحميل الصور في واجهة المستخدم التصريحية. تقبل أي مصدر بيانات وثلاث معاملات اختيارية للحالات: placeholder و error و success.

kotlin
@Composable
fun NetworkImage(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "صورة الشبكة",
        placeholder = ColorPainter(Color.Gray),
        error = ColorPainter(Color.Red)
    )
}

SubcomposeAsyncImage هي نسخة أكثر مرونة تسمح بتخصيص العرض أثناء التحميل من خلال فتحة المحتوى. هذا مفيد للهياكل العظمية (shimmer) وأشرطة التقدم.

Target مخصص لإخراج غير قياسي

إذا لم يكن ImageView أو AsyncImage مناسبين، يمكن تنفيذ Target بطريقة onSuccess واحدة تقبل Bitmap. يُستخدم هذا للتحميل في Notification أو RemoteViews أو نسيج OpenGL.

kotlin
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 مع المكتبات الأخرى

يعتمد اختيار مكتبة تحميل الصور على متطلبات المشروع. تتنافس Coil مع Glide و Picasso، لكل منهما نقاط قوته. يُعرض جدول مقارنة الخصائص الرئيسية.

الخاصيةCoilGlidePicasso
اللغةKotlin (100%)Java + KotlinJava
حجم APK~150 كيلوبايت~500 كيلوبايت~120 كيلوبايت
Coroutinesمضمنةلا (استرجاعات)لا (استرجاعات)
Jetpack Composeدعم أصليعبر accompanistجهة خارجية
GIF/WebPنعم (مضمن)نعم (مضمن)لا
توصية Googleنعم (I/O 2023)نعملا

للمشاريع الجديدة على Kotlin و Jetpack Compose، يصبح Coil الخيار الطبيعي بفضل عدم وجود تبعيات إضافية للـ coroutines والحجم الصغير. يبقى Glide مفضلاً للسيناريوهات المعقدة مع الرسوم المتحركة ومعاينات الفيديو. Picasso أقل من كليهما في الوظائف لكنه يفوز في البساطة.

إعداد Coil في مشروع Android

يتم إضافة Coil إلى مشروع Android عبر تبعية Gradle. بعد الإضافة، تقوم المكتبة بتسجيل ImageLoader تلقائياً عبر ContentProvider، لذلك لا يلزم التهيئة اليدوية في Application. إذا كانت هناك حاجة للتخصيص، يتم إنشاء ImageLoader مخصص عبر builder.

kotlin
// 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 مع مجموعة اتصالات جاهزة.

kotlin
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 وما هي استخداماته؟

Coil هي مكتبة لتحميل الصور على Android، مكتوبة بلغة Kotlin باستخدام coroutines. تُستخدم للتحميل غير المتزامن والتخزين المؤقت وعرض الصور النقطية من الشبكة أو الموارد أو نظام الملفات.

ما الفرق بين Coil و Glide؟

Coil مكتوب 100% بلغة Kotlin ويستخدم coroutines بدلاً من آلية الاسترجاعات في Glide. Coil له حجم APK أصغر (~150 كيلوبايت مقابل ~500 كيلوبايت) ودعم أصلي لـ Jetpack Compose عبر AsyncImage.

كيفية إضافة Coil إلى مشروع Kotlin؟

أضف التبعية io.coil-kt:coil:2.6.0 إلى build.gradle.kts. لـ Jetpack Compose، أضف أيضاً io.coil-kt:coil-compose:2.6.0. المكتبة تسجل ImageLoader تلقائياً عبر ContentProvider.

ما أنواع الصور التي يدعمها Coil؟

Coil يدعم JPEG و PNG و WebP و BMP و SVG (عبر وحدة coil-svg) و GIF (عبر وحدة coil-gif). يتم دعم صيغ AVIF و HEIF عبر مفكك مخصص على الأجهزة التي تعمل بنظام Android 10+.

كيفية تكوين التخزين المؤقت في Coil؟

يتم تكوين التخزين المؤقت عبر ImageLoader.Builder: memoryCache بتحديد النسبة المئوية من heap، diskCache مع المسار والحد بالبايت. سياسات التخزين المؤقت (ENABLED و DISABLED و READ_ONLY) تُكوّن لكل طلب عبر CachePolicy.

الملخص

  • Coil هي مكتبة تحميل صور لـ Kotlin مع دعم كامل للـ coroutines و Jetpack Compose.
  • ImageLoader يدير الطلبات والتخزين المؤقت والتحويلات، باستخدام مستويين من التخزين المؤقت: Memory Cache و Disk Cache.
  • AsyncImage و SubcomposeAsyncImage توفران التكامل مع Compose، وتدعمان حالات placeholder و error و success.
  • حجم APK ~150 كيلوبايت يجعل Coil واحدة من أكثر مكتبات تحميل الصور اكتنازاً في السوق.
  • التحويلات (RoundedCorners و CircleCrop و Blur) مدمجة في المكتبة وتعمل مع تسريع الأجهزة.
  • Disk Cache يوفر وصولاً دون اتصال للصور المحملة مسبقاً بحد تخزين قابل للتكوين.
  • Coil موصى به من Google في الأدلة الرسمية لـ Jetpack Compose، مما يؤكد مكانته كمعيار حديث.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا