0Pricing
Android Academy · درس

لماذا نستخدم Paging

تكلفة تحميل كل شيء دفعة واحدة

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

تحميل كل شيء مكلف

تخيّل موجزًا يضم 50,000 عنصر. إذا جلبتها واحتفظت بها جميعًا دفعة واحدة، فستستهلك الذاكرة بلا داعٍ، وتبطئ الشبكة، وتجمّد واجهة المستخدم أثناء تحليل الاستجابة.

لا يتصفح معظم المستخدمين سوى الشاشات القليلة الأولى. يعني Paging تحميل البيانات على دفعات صغيرة (صفحات) أثناء تمرير المستخدم، بدلًا من تحميلها كلها مسبقًا.

المشكلة في الشيفرة

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

لا يتوسع هذا النمط بشكل جيد، وقد يتسبب في OutOfMemoryError عند التعامل مع مجموعات بيانات كبيرة.

// Anti-pattern: load the whole table at once
suspend fun loadAllArticles(): List<Article> {
    // Could be tens of thousands of rows / megabytes of JSON
    return api.getArticles(limit = 50_000)
}

// UI holds ALL of them in memory at once
val articles = loadAllArticles()
LazyColumn {
    items(articles) { article -> ArticleRow(article) }
}

كيف تبدو الصفحة

الصفحة هي جزء صغير من مجموعة البيانات، وغالبًا ما تتكون من 20 إلى 50 عنصرًا. يعيد الخادم صفحةً واحدةً بالإضافة إلى مؤشر للصفحة التالية، مثل رقم أو إزاحة أو رمز مميز.

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

data class ArticlePage(
    val items: List<Article>,
    val nextKey: Int?   // null means no more pages
)

// Example REST call returning one page
suspend fun getArticlePage(page: Int, size: Int = 20): ArticlePage

التعرّف إلى Paging 3

Paging 3 هي مكتبة Jetpack التي تتولى عنكم جميع الأجزاء المعقدة من تقسيم الصفحات:

  • طلب الصفحة التالية عندما يقترب المستخدم من نهاية القائمة
  • الاحتفاظ بنافذة من العناصر فقط في الذاكرة
  • إتاحة حالات التحميل والخطأ
  • دعم مدمج لـ coroutines وFlow وJetpack Compose

إضافة الاعتمادية

تأتي Paging 3 على هيئة artifacts منفصلة: وقت تشغيل وتكامل مع Compose. أضيفوهما في build.gradle.kts الخاص بالوحدة.

يوفر artifact المسمى paging-compose أدوات مساعدة لـ LazyColumn.

// build.gradle.kts (module)
dependencies {
    val pagingVersion = "3.3.6"
    implementation("androidx.paging:paging-runtime:$pagingVersion")
    implementation("androidx.paging:paging-compose:$pagingVersion")
}

الأجزاء الأساسية الثلاثة

تتمحور Paging 3 حول ثلاثة أنواع ستستخدمونها مرارًا:

  • PagingSource - يعرف كيفية تحميل صفحة واحدة من مصدر
  • Pager - يضبط تدفق البيانات المقسمة إلى صفحات وينتجه
  • PagingData - حاوية للعناصر، تُصدر على هيئة Flow

سننشئ كل واحد من هذه الأجزاء في الدروس التالية.

PagingData وFlow

يكشف المستودع لديكم عن Flow<PagingData<T>>. وتجمعه واجهة المستخدم لعرض العناصر المحمّلة حاليًا.

لن تضطروا أبدًا إلى تجميع القائمة كاملة بأنفسكم؛ إذ تبث Paging العناصر إلى واجهة المستخدم عند الطلب.

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow

class ArticleRepository(private val api: ArticleApi) {
    fun articles(): Flow<PagingData<Article>> = Pager(
        config = PagingConfig(pageSize = 20)
    ) {
        ArticlePagingSource(api)
    }.flow
}

يتحكم PagingConfig في النافذة

يضبط PagingConfig كيفية تحميل Paging للبيانات والاحتفاظ بها:

  • pageSize - عدد العناصر في كل طلب صفحة
  • prefetchDistance - المسافة من الحافة التي تؤدي إلى تشغيل التحميل التالي
  • enablePlaceholders - عرض مواضع بديلة للعناصر التي لم تُحمّل بعد
  • maxSize - الحد الأقصى لعدد العناصر المحتفظ بها في الذاكرة
import androidx.paging.PagingConfig

val config = PagingConfig(
    pageSize = 20,
    prefetchDistance = 5,
    enablePlaceholders = false,
    maxSize = 100
)

الشبكة أو قاعدة البيانات أو كلتاهما

يمكن لـ PagingSource جلب البيانات من REST API أو قاعدة بيانات Room أو أي مصدر مخصص.

للحصول على تجربة حقيقية تبدأ بالعمل دون اتصال، ادمجوا المصدرين باستخدام RemoteMediator (وسنتناوله في الدرس الأخير): تملأ الشبكة قاعدة بيانات محلية، وتعرض واجهة المستخدم الصفحات من قاعدة البيانات تلك.

تمرير سلس واستهلاك أقل للذاكرة

مع تقسيم الصفحات، يظل التمرير سلسًا لأن كل طلب صغير، ولأن نافذة البيانات الموجودة في الذاكرة محدودة بواسطة maxSize.

تتوفر مؤشرات التحميل والأخطاء تلقائيًا من خلال LoadState، لذا يمكنكم عرض مؤشر تحميل في الأسفل أو زر لإعادة المحاولة دون إدارة يدوية.

// LoadState exposes loading/error per direction
when (val state = adapterLoadState.append) {
    is LoadState.Loading -> showBottomSpinner()
    is LoadState.Error -> showRetry(state.error)
    is LoadState.NotLoading -> hideBottomSpinner()
}

متى تحتاجون إلى Paging

استخدموا Paging 3 عندما:

  • تكون مجموعة البيانات كبيرة أو غير محدودة، مثل الخلاصات ونتائج البحث وسجل المحادثات
  • تأتي البيانات من network API يعيد صفحات أو مؤشرات
  • تريدون واجهة تلقائية للتحميل والأخطاء والتحكم في الذاكرة

أما بالنسبة إلى قائمة قصيرة وثابتة، مثل قائمة الإعدادات، فإن استخدام LazyColumn العادي أبسط ومناسب تمامًا.

تحقق سريع

ما الفائدة الأساسية من استخدام Paging 3 مع قائمة كبيرة؟

مراجعة: لماذا نستخدم Paging

تعلمتم لماذا يؤدي تحميل كل شيء دفعةً واحدة إلى الإضرار بالأداء والذاكرة، وكيف تحل Paging 3 هذه المشكلة.

  • تُحمّل البيانات في صفحات صغيرة أثناء تمرير المستخدم
  • الأجزاء الأساسية الثلاثة هي PagingSource وPager وPagingData
  • يضبط PagingConfig حجم الصفحة والتحميل المسبق ونافذة الذاكرة
  • تتكامل Paging مع coroutines وFlow وCompose، وتوفر حالات التحميل والأخطاء تلقائيًا

التالي: إنشاء PagingSource وربطه بـ Pager.

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

هل درس «لماذا نستخدم Paging» مجاني؟

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

ماذا ستتعلم في «لماذا نستخدم Paging»؟

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

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

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

كم من الوقت يستغرق درس «لماذا نستخدم Paging»؟

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

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

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

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

  1. لماذا نستخدم Paging
  2. PagingSource وPager
  3. Paging في قوائم Compose
  4. RemoteMediator والتخزين المؤقت
← العودة إلى Android Academy