0Pricing
Android Academy · درس

العناصر النائبة وحالات الخطأ

تعامل بسلاسة مع التحميل والإخفاقات

العناصر النائبة وحالات الخطأ درس مجاني في Android Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Android Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Android Academy 4 دروس في المجموع.

التحميل ليس فوريًا

تحتاج الصور الشبكية إلى وقت. وخلال هذه الفترة تعرض واجهة المستخدم... لا شيء، ما لم تتعامل مع الأمر. وأحيانًا لا تصل الصورة أبدًا: قد يكون عنوان URL معطّلًا، أو الخادم متوقفًا، أو المستخدم غير متصل بالإنترنت.

يعرض التطبيق المصقول عنصرًا نائبًا أثناء التحميل وبديلًا عند الفشل، بدلًا من ترك فراغ أو التسبب في تعطل التطبيق. ويجعل Coil كلا الأمرين سهلًا.

في هذا الدرس ستضيف عناصر نائبة وصورًا للأخطاء وواجهة مستخدم مخصصة لكل حالة.

عنصر نائب بسيط

أسرع طريقة لإضافة عنصر نائب هي تمرير عنصر قابل للرسم إلى AsyncImage عبر المعامل placeholder باستخدام painterResource. يعرضه Coil إلى أن تنتهي الصورة الحقيقية من التحميل.

استخدم عنصرًا قابلًا للرسم محايدًا وخفيفًا، مثل مربع رمادي أو صورة ظلية لشعار.

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage

@Composable
fun ImageWithPlaceholder(url: String) {
    AsyncImage(
        model = url,
        contentDescription = null,
        placeholder = painterResource(R.drawable.placeholder_gray)
    )
}

إضافة صورة للخطأ

يعرض المعامل error عنصرًا قابلًا للرسم كبديل عند فشل الطلب. وهناك أيضًا fallback، ويُستخدم تحديدًا عندما تكون قيمة model هي null، أي عندما لا توجد بيانات للتحميل أصلًا.

يضمن ضبط الحالات الثلاث، وهي placeholder وerror وfallback، تغطية كل حالة مرئية تقريبًا دون كتابة أي شيفرة إضافية.

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage

@Composable
fun RobustImage(url: String?) {
    AsyncImage(
        model = url,
        contentDescription = null,
        placeholder = painterResource(R.drawable.placeholder_gray),
        error = painterResource(R.drawable.image_broken),
        fallback = painterResource(R.drawable.no_image)
    )
}

العنصر النائب عبر ImageRequest

يمكنك أيضًا ضبط هذه الحالات في ImageRequest نفسه. ويكون ذلك مفيدًا عندما تنشئ الطلب مرة واحدة وتعيد استخدامه، أو عندما تحتاج إلى خيارات طلب أخرى في الوقت نفسه.

تأخذ الدوال الموجودة على مستوى الطلب معرّفات الموارد القابلة للرسم.

import android.content.Context
import coil3.request.ImageRequest
import coil3.request.crossfade
import coil3.request.error
import coil3.request.placeholder

fun buildRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .crossfade(true)
        .placeholder(R.drawable.placeholder_gray)
        .error(R.drawable.image_broken)
        .build()

واجهة مستخدم مخصصة باستخدام SubcomposeAsyncImage

العناصر القابلة للرسم مناسبة، لكنك قد ترغب أحيانًا في عرض مؤشر انتظار أو لمعان أو نص لكل حالة. يتيح لك SubcomposeAsyncImage توفير عناصر قابلة للتركيب فعلية للحالات loading وerror وsuccess.

يوفر ذلك مرونة أكبر لكنه أثقل قليلًا، لذا يُفضل استخدام العناصر النائبة القابلة للرسم في القوائم الطويلة، وحصر التركيب الفرعي في الصور الرئيسية.

import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage

@Composable
fun HeroImage(url: String) {
    SubcomposeAsyncImage(
        model = url,
        contentDescription = "Hero",
        loading = { CircularProgressIndicator() },
        error = { Text("Could not load image") }
    )
}

قراءة الحالة مباشرة

للحصول على تحكم كامل، استخدم واجهة برمجة التطبيقات rememberAsyncImagePainter وافحص state الخاص بها. الحالة نوع مختوم يضم الحالات Loading وSuccess وError وEmpty.

يتيح لك ذلك التحكم في التخطيط أو الحركات أو التحليلات الخاصة بك استنادًا إلى ما حدث.

import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImagePainter
import coil3.compose.rememberAsyncImagePainter

@Composable
fun StateAwareImage(url: String) {
    val painter = rememberAsyncImagePainter(model = url)
    val state = painter.state.collectAsState().value

    when (state) {
        is AsyncImagePainter.State.Loading -> { /* show spinner */ }
        is AsyncImagePainter.State.Error -> { /* show error UI */ }
        else -> Image(painter = painter, contentDescription = null)
    }
}

عرض عنصر نائب بلمعان

من الأنماط الشائعة اللمعان، وهو تدرج رمادي متحرك يوحي بأن المحتوى قادم. يمكنك إنشاء نسخة بسيطة منه باستخدام مربع ذي لون ثابت خلف حالة التحميل.

نستخدم هنا SubcomposeAsyncImage مع مربع ملوّن أثناء التحميل. استبدل المربع بمكتبة لمعان إذا أردت التأثير المتحرك.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import coil3.compose.SubcomposeAsyncImage

@Composable
fun ShimmerImage(url: String) {
    SubcomposeAsyncImage(
        model = url,
        contentDescription = null,
        loading = {
            androidx.compose.foundation.layout.Box(
                Modifier.fillMaxSize()
                    .background(MaterialTheme.colorScheme.surfaceVariant)
            )
        }
    )
}

التعامل مع نموذج null أو الفارغ

ماذا لو لم يكن لديك عنوان URL بعد، مثل مستخدم لا يملك صورة ملف شخصي؟ يؤدي تمرير null بوصفه النموذج إلى تشغيل العنصر القابل للرسم fallback، أو error إذا لم يتم تعيين fallback.

يمنع ذلك الحاجة إلى معالجة null بصورة خاصة في شيفرتك؛ دع Coil يعرض صورة رمزية افتراضية.

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage

@Composable
fun ProfilePicture(photoUrl: String?) {
    // If photoUrl is null, Coil shows the fallback default avatar.
    AsyncImage(
        model = photoUrl,
        contentDescription = "Profile picture",
        fallback = painterResource(R.drawable.default_avatar),
        error = painterResource(R.drawable.default_avatar)
    )
}

الاستماع إلى الأخطاء باستخدام مستمع

قد تحتاج أحيانًا إلى التفاعل برمجيًا عند فشل التحميل، مثل تسجيل الخطأ أو إعادة المحاولة. يقبل ImageRequest.Builder مستمعًا listener مع استدعاءات نجاح وخطأ.

اجعل هذه الاستدعاءات خفيفة؛ فهي تعمل على الخيط الرئيسي.

import android.content.Context
import android.util.Log
import coil3.request.ImageRequest

fun loggedRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .listener(
            onError = { _, result ->
                Log.e("Coil", "Load failed", result.throwable)
            },
            onSuccess = { _, _ ->
                Log.d("Coil", "Loaded $url")
            }
        )
        .build()

تلوين مرشحات الألوان

غالبًا ما تبدو العناصر القابلة للرسم الخاصة بالعناصر النائبة والأخطاء أفضل عند تلوينها بما يتوافق مع نسقك. يمكنك تطبيق ColorFilter على AsyncImage، وهو مناسب جدًا للبدائل ذات نمط الأيقونات أحادية اللون التي ينبغي أن تتكيف مع الوضعين الفاتح والداكن.

طبّق المرشح فقط على مظهر العنصر النائب أو الخطأ الذي تريده؛ أما الصور الحقيقية فعادةً ما تتركها من دونه.

import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage

@Composable
fun TintedFallback(url: String?) {
    AsyncImage(
        model = url,
        contentDescription = null,
        error = painterResource(R.drawable.ic_image_placeholder),
        colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant)
    )
}

مكوّن صور متين

لنجمع كل ذلك في مكوّن قابل لإعادة الاستخدام يتعامل مع كل حالة بوضوح: خلفية أثناء التحميل، وبديل عند الخطأ، وتلاشي متقاطع، واقتصاص. أضف هذا إلى قائمة ولن تقلق مجددًا بشأن الفراغات الناتجة عن الصور.

import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ResilientImage(url: String?, size: Int = 96) {
    val context = LocalContext.current
    AsyncImage(
        model = ImageRequest.Builder(context)
            .data(url)
            .crossfade(true)
            .build(),
        contentDescription = null,
        contentScale = ContentScale.Crop,
        placeholder = painterResource(R.drawable.placeholder_gray),
        error = painterResource(R.drawable.image_broken),
        fallback = painterResource(R.drawable.default_avatar),
        modifier = Modifier.size(size.dp)
    )
}

اختبار سريع

تمرير model = null إلى AsyncImage. ما الرسم الذي يعرضه Coil افتراضيًا؟

مراجعة

لقد جعلتم تحميل الصور أكثر سلاسة. النقاط الأساسية:

  • يعرض placeholder صورةً مؤقتة أثناء التحميل، ويُستخدم error عند الفشل، بينما يُستخدم fallback عندما تكون قيمة النموذج null.
  • يمكنكم ضبطها على AsyncImage أو على ImageRequest.
  • يتيح لكم SubcomposeAsyncImage توفير composables فعلية، مثل مؤشر التحميل أو تأثير الوميض، لكل حالة.
  • يكشف rememberAsyncImagePainter عن state الخام لمنحكم تحكمًا كاملًا.
  • استخدموا listener الخاص بالطلب لتسجيل نتائج التحميل أو الاستجابة لها.

التالي: التخزين المؤقت والأداء، حتى تُحمَّل الصور فورًا في المرة الثانية.

الأسئلة الشائعة

هل درس «العناصر النائبة وحالات الخطأ» مجاني؟

نعم — نص درس «العناصر النائبة وحالات الخطأ» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Android Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Android Academy 4 دروس في المجموع.

ماذا ستتعلم في «العناصر النائبة وحالات الخطأ»؟

تعامل بسلاسة مع التحميل والإخفاقات تتمرن على Android Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Android Academy؟

لا تُشترط خبرة سابقة. Android Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «العناصر النائبة وحالات الخطأ»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Android Academy هذا؟

نعم. كل درس في Android Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تحميل الصور باستخدام Coil
  2. العناصر النائبة وحالات الخطأ
  3. التخزين المؤقت والأداء
  4. تشغيل الصوت والفيديو
← العودة إلى Android Academy