Paging 3 في Kotlin: دليل شامل مع أمثلة عملية
1. ما هي Paging 3 ولماذا تحتاجها؟
Paging 3 هي مكتبة من Google لتطبيقات Android، مكتوبة بلغة Kotlin، وتحل واحدة من أكثر المشاكل شيوعًا في تطوير التطبيقات: تحميل البيانات على دفعات (pagination). عندما يكون لديك قائمة تحتوي على آلاف أو ملايين العناصر (مثل: قائمة الأخبار، رسائل الدردشة، منتجات المتجر)، فإن تحميلها كلها مرة واحدة أمر مستحيل - سيؤدي ذلك إلى استنزاف الذاكرة، وتجميد واجهة المستخدم، واستهلاك كبير للبيانات. تقوم Paging 3 بأتمتة عملية تحميل البيانات على دفعات (صفحات) أثناء قيام المستخدم بالتمرير في القائمة.
المكتبة مبنية على أحدث المبادئ: تستخدم Kotlin Coroutines للعمل غير المتزامن، و Flow لتحديث البيانات بشكل تفاعلي، وتتكامل بشكل كامل مع Jetpack Compose و RecyclerView. على عكس الإصدارات السابقة (Paging 2)، تقدم Paging 3 بنية أنظف، وكودًا أقل، ودعمًا مدمجًا لمعالجة الأخطاء وتحديث البيانات والتخزين المؤقت.
القيمة الأساسية لـ Paging 3: أنت تكتب منطق تحميل صفحة واحدة فقط (مثل طلب API)، والمكتبة تتولى بنفسها تحديد موعد تحميل الصفحة التالية، وكيفية تخزين البيانات في الذاكرة، وكيفية إعلام المحول (Adapter) بالتغييرات، وكيفية التعامل مع حالات التحميل (جارٍ التحميل، خطأ، قائمة فارغة). هذا يوفر ساعات من التطوير ويجعل تطبيقك مستقرًا حتى مع مجموعات البيانات الضخمة.
2. التثبيت
Paging 3 هي مكتبة خاصة بـ Android/Kotlin، لذا يتم تثبيتها عبر نظام بناء Gradle، وليس عبر pip أو npm. أضف التبعية (dependency) إلى ملف build.gradle.kts (موديول التطبيق):
// build.gradle.kts (Module: app)
dependencies {
// المكتبة الأساسية لـ Paging 3
implementation("androidx.paging:paging-runtime-ktx:3.3.5")
// إذا كنت تستخدم Jetpack Compose (اختياري)
implementation("androidx.paging:paging-compose:3.3.5")
// إذا كنت تستخدم RxJava (اختياري)
implementation("androidx.paging:paging-rxjava3:3.3.5")
// للاختبار (اختياري)
testImplementation("androidx.paging:paging-common:3.3.5")
}
بعد مزامنة Gradle، تصبح المكتبة جاهزة للاستخدام. الحد الأدنى لإصدار SDK هو 21 (Android 5.0).
3. البداية السريعة - مثال عملي بسيط
لنقم بإنشاء شاشة بسيطة تقوم بتحميل قائمة من الأرقام من 1 إلى 1000، بمعدل 20 عنصرًا في كل صفحة. يتكون المثال من ثلاثة أجزاء: مصدر البيانات (PagingSource)، وViewModel، وواجهة المستخدم (RecyclerView).
الخطوة 1: PagingSource - مصدر البيانات
class NumberPagingSource : PagingSource<Int, Int>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Int> {
return try {
// تحديد مفتاح الصفحة التالية (إذا كان null فهذا يعني التحميل الأول)
val currentPage = params.key ?: 0
val pageSize = params.loadSize // عادة 20
// توليد البيانات للصفحة الحالية
val start = currentPage * pageSize
val end = minOf(start + pageSize, 1000)
val numbers = (start until end).toList()
// إرجاع النتيجة مع مفاتيح الصفحة التالية والسابقة
LoadResult.Page(
data = numbers,
prevKey = if (currentPage > 0) currentPage - 1 else null,
nextKey = if (end < 1000) currentPage + 1 else null
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
// إرجاع مفتاح إعادة التحميل (عادة null أو المفتاح الأول)
override fun getRefreshKey(state: PagingState<Int, Int>): Int? = null
}
الخطوة 2: ViewModel
class MainViewModel : ViewModel() {
val pager = Pager(
config = PagingConfig(pageSize = 20, enablePlaceholders = f