‫Android Kotlin Fundamentals 07.2: DiffUtil وربط البيانات باستخدام RecyclerView

هذا الدرس التطبيقي حول الترميز هو جزء من دورة "أساسيات Android Kotlin". يمكنك تحقيق أقصى استفادة من هذه الدورة التدريبية إذا اتبعت ترتيب الخطوات في دروس البرمجة. يتم إدراج جميع الدروس التطبيقية حول الترميز الخاصة بالدورة التدريبية في الصفحة المقصودة للدروس التطبيقية حول الترميز في دورة Android Kotlin Fundamentals.

مقدمة

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

في هذا الدرس التطبيقي حول الترميز، ستستند إلى تطبيق "متتبّع النوم" من الدرس التطبيقي السابق حول الترميز. ستتعرّف على طريقة أكثر فعالية لتعديل قائمة بيانات النوم، وكيفية استخدام ربط البيانات مع RecyclerView. (إذا لم يكن لديك التطبيق من الدرس العملي السابق، يمكنك تنزيل رمز البداية لهذا الدرس العملي).

ما يجب معرفته

  • إنشاء واجهة مستخدم أساسية باستخدام نشاط وقِطع وعناصر عرض
  • التنقّل بين الأجزاء واستخدام safeArgs لنقل البيانات بين الأجزاء
  • عرض النماذج وعوامل إنشاء النماذج وعمليات التحويل وLiveData والمراقبين المرتبطين بها
  • كيفية إنشاء قاعدة بيانات Room وإنشاء كائن وصول إلى البيانات (DAO) وتحديد الكيانات
  • كيفية استخدام الروتينات المشتركة لقاعدة البيانات والمهام الأخرى التي تستغرق وقتًا طويلاً
  • كيفية تنفيذ RecyclerView أساسي باستخدام Adapter وViewHolder وتنسيق العناصر

أهداف الدورة التعليمية

  • كيفية استخدام DiffUtil لتعديل قائمة معروضة بواسطة RecyclerView بكفاءة
  • كيفية استخدام ربط البيانات مع RecyclerView
  • كيفية استخدام أدوات ربط البيانات لتحويل البيانات

الإجراءات التي ستنفذّها

  • يمكنك الاستناد إلى تطبيق TrackMySleepQuality من الدرس التطبيقي السابق في هذه السلسلة.
  • عدِّل SleepNightAdapter لتعديل القائمة بكفاءة باستخدام DiffUtil.
  • نفِّذ ربط البيانات للعنصر RecyclerView، وذلك باستخدام أدوات ربط البيانات لتحويل البيانات.

يحتوي تطبيق تتبُّع النوم على شاشتَين، يتم تمثيلهما بلقطات، كما هو موضّح في الشكل أدناه.

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

تم تصميم هذا التطبيق لاستخدام وحدة تحكّم في واجهة المستخدم، وViewModel، وLiveData، وقاعدة بيانات Room لتخزين بيانات النوم بشكل دائم.

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

يمكنك مواصلة استخدام تطبيق SleepTracker من الدرس العملي السابق، أو يمكنك تنزيل تطبيق RecyclerViewDiffUtilDataBinding-Starter من GitHub.

  1. إذا لزم الأمر، نزِّل تطبيق RecyclerViewDiffUtilDataBinding-Starter من GitHub وافتح المشروع في Android Studio.
  2. شغِّل التطبيق.
  3. افتح ملف SleepNightAdapter.kt.
  4. افحص الرمز البرمجي للتعرّف على بنية التطبيق. راجِع الرسم البياني أدناه للحصول على ملخّص حول استخدام RecyclerView مع نمط المحوّل لعرض بيانات النوم للمستخدم.

  • من إدخال المستخدم، ينشئ التطبيق قائمة بعناصر SleepNight. يمثّل كل عنصر SleepNight ليلة نوم واحدة ومدتها وجودتها.
  • يحوّل SleepNightAdapter قائمة عناصر SleepNight إلى تنسيق يمكن أن يستخدمه RecyclerView ويعرضه.
  • ينتج محوّل SleepNightAdapter ViewHolders يحتوي على طرق العرض والبيانات والمعلومات الوصفية الخاصة بطريقة العرض القابلة لإعادة الاستخدام لعرض البيانات.
  • تستخدم RecyclerView SleepNightAdapter لتحديد عدد العناصر المطلوب عرضها (getItemCount())، كما تستخدم RecyclerView onCreateViewHolder() وonBindViewHolder() للحصول على عناصر نائبة لعرض البيانات.

الطريقة notifyDataSetChanged() غير فعّالة

لإخبار RecyclerView بأنّ أحد العناصر في القائمة قد تغيّر ويجب تعديله، يستدعي الرمز الحالي notifyDataSetChanged() في SleepNightAdapter، كما هو موضّح أدناه.

var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

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

لحلّ هذه المشكلة، يمكنك إخبار RecyclerView بالتغييرات التي تم إجراؤها بالضبط. يمكن لـ RecyclerView بعد ذلك تعديل طرق العرض التي تم تغييرها على الشاشة فقط.

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

لحسن الحظ، هناك طريقة أفضل.

تتسم أداة DiffUtil بالكفاءة وتتولى عنك المهام الشاقة

يحتوي RecyclerView على فئة تُسمى DiffUtil، وهي مخصّصة لاحتساب الفروق بين قائمتَين. تأخذ DiffUtil قائمة قديمة وقائمة جديدة وتحدّد العناصر المختلفة بينهما. تعثر هذه الطريقة على العناصر التي تمت إضافتها أو إزالتها أو تغييرها. بعد ذلك، تستخدم خوارزمية تُعرف باسم Eugene W. خوارزمية الفرق بين مايرز لمعرفة الحد الأدنى لعدد التغييرات التي يجب إجراؤها من القائمة القديمة لإنشاء القائمة الجديدة

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

في هذه المهمة، ستتم ترقية SleepNightAdapter لاستخدام DiffUtil من أجل تحسين RecyclerView لإجراء تغييرات على البيانات.

الخطوة 1: تنفيذ SleepNightDiffCallback

لاستخدام وظائف الفئة DiffUtil، عليك توسيع DiffUtil.ItemCallback.

  1. فتح "SleepNightAdapter.kt"
  2. أسفل تعريف الفئة الكامل لـ SleepNightAdapter، أنشئ فئة جديدة ذات مستوى أعلى باسم SleepNightDiffCallback تتضمّن DiffUtil.ItemCallback. مرِّر SleepNight كمعلَمة عامة.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
  1. ضَع المؤشر في اسم الفئة SleepNightDiffCallback.
  2. اضغط على Alt+Enter (Option+Enter على جهاز Mac) واختَر تنفيذ الأعضاء.
  3. في مربّع الحوار الذي يظهر، اضغط على Shift مع النقر بزر الماوس الأيسر لاختيار الطريقتَين areItemsTheSame() وareContentsTheSame()، ثم انقر على حسنًا.

    سيؤدي ذلك إلى إنشاء رموز صورية داخل SleepNightDiffCallback للطريقتَين، كما هو موضّح أدناه. تستخدم DiffUtil هاتين الطريقتين لمعرفة كيفية تغيير القائمة والعناصر.
    override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
  1. داخل areItemsTheSame()، استبدِل TODO بالرمز الذي يختبر ما إذا كان العنصران SleepNight اللذان تم تمريرهما، oldItem وnewItem، متطابقَين. إذا كانت العناصر تتضمّن nightId نفسه، تكون هي نفسها، لذا يجب عرض true. بخلاف ذلك، أعِد false. تستخدم DiffUtil هذا الاختبار للمساعدة في معرفة ما إذا تمت إضافة عنصر أو إزالته أو نقله.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem.nightId == newItem.nightId
}
  1. داخل areContentsTheSame()، تحقَّق مما إذا كان oldItem وnewItem يحتويان على البيانات نفسها، أي ما إذا كانا متساويين. سيتحقّق هذا الاختبار من المساواة من جميع الحقول، لأنّ SleepNight هو فئة بيانات. تحدّد فئات Data تلقائيًا equals وبعض الطرق الأخرى. إذا كانت هناك اختلافات بين oldItem وnewItem، يخبر هذا الرمز DiffUtil بأنّه تم تعديل العنصر.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem == newItem
}

من الأنماط الشائعة استخدام RecyclerView لعرض قائمة تتغيّر. توفّر RecyclerView فئة محوّل، ListAdapter، تساعدك في إنشاء محوّل RecyclerView يستند إلى قائمة.

تتتبّع ListAdapter القائمة نيابةً عنك وتُعلم المحوّل عند تعديل القائمة.

الخطوة 1: تغيير المحوّل لتوسيع ListAdapter

  1. في الملف SleepNightAdapter.kt، غيِّر توقيع الفئة SleepNightAdapter لتوسيع ListAdapter.
  2. إذا طُلب منك ذلك، استورِد androidx.recyclerview.widget.ListAdapter.
  3. أضِف SleepNight كمعلَمة أولى إلى ListAdapter، قبل SleepNightAdapter.ViewHolder.
  4. أضِف SleepNightDiffCallback() كمَعلمة إلى الدالة الإنشائية. سيستخدم ListAdapter هذا لتحديد التغييرات التي تم إجراؤها في القائمة. يجب أن تبدو توقيعات فئة SleepNightAdapter المكتملة كما هو موضّح أدناه.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
  1. داخل فئة SleepNightAdapter، احذف الحقل data، بما في ذلك الدالة الضابطة. لن تحتاج إليها بعد الآن، لأنّ ListAdapter يتتبّع القائمة نيابةً عنك.
  2. احذف عملية الإلغاء الخاصة بـ getItemCount()، لأنّ ListAdapter تنفّذ هذه الطريقة نيابةً عنك.
  3. للتخلّص من الخطأ في onBindViewHolder()، غيِّر المتغيّر item. بدلاً من استخدام data للحصول على item، استدعِ طريقة getItem(position) التي يوفّرها ListAdapter.
val item = getItem(position)

الخطوة 2: استخدام submitList() لإبقاء القائمة محدَّثة

يجب أن يوضّح الرمز البرمجي ListAdapter أنّه تتوفّر قائمة معدَّلة. توفّر ListAdapter طريقة تُسمى submitList() لإعلام ListAdapter بأنّه يتوفّر إصدار جديد من القائمة. عند استدعاء هذه الطريقة، تقارن ListAdapter القائمة الجديدة بالقائمة القديمة وترصد العناصر التي تمت إضافتها أو إزالتها أو نقلها أو تغييرها. بعد ذلك، ListAdapter تعدّل السلع المعروضة من خلال RecyclerView.

  1. فتح "SleepTrackerFragment.kt"
  2. في onCreateView()، في أداة المراقبة على sleepTrackerViewModel، ابحث عن الخطأ الذي تتم فيه الإشارة إلى المتغيّر data الذي حذفْته.
  3. استبدِل adapter.data = it بمكالمة إلى adapter.submitList(it). يظهر الرمز المعدَّل أدناه.

sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.submitList(it)
   }
})
  1. شغِّل تطبيقك، وسيتم تشغيله بشكل أسرع، ولكن قد لا يكون ذلك ملحوظًا إذا كانت قائمتك صغيرة.

في هذه المهمة، ستستخدم الأسلوب نفسه المستخدَم في دروس البرمجة السابقة لإعداد ربط البيانات، وستتخلّص من طلبات findViewById().

الخطوة 1: إضافة ربط البيانات إلى ملف التنسيق

  1. افتح ملف التنسيق list_item_sleep_night.xml في علامة التبويب نص.
  2. ضَع المؤشر على العلامة ConstraintLayout واضغط على Alt+Enter (Option+Enter على جهاز Mac). يتم فتح قائمة الإجراءات المقصودة (قائمة "الإصلاح السريع").
  3. اختَر التحويل إلى تنسيق ربط البيانات. يؤدي ذلك إلى تضمين التنسيق في <layout> وإضافة علامة <data> في الداخل.
  4. ارجع إلى أعلى الصفحة، إذا لزم الأمر، وفي علامة <data>، عرِّف متغيّرًا باسم sleep.
  5. اجعل type هو الاسم المؤهّل بالكامل لـ SleepNight، com.example.android.trackmysleepquality.database.SleepNight. يجب أن تبدو علامة <data> المكتملة كما هو موضّح أدناه.
   <data>
        <variable
            name="sleep"
            type="com.example.android.trackmysleepquality.database.SleepNight"/>
    </data>
  1. لفرض إنشاء العنصر Binding، اختَر إنشاء > تنظيف المشروع، ثم اختَر إنشاء > إعادة إنشاء المشروع. (إذا كنت لا تزال تواجه مشاكل، اختَر ملف > إبطال ذاكرات التخزين المؤقت / إعادة التشغيل). تتم إضافة عنصر الربط ListItemSleepNightBinding، بالإضافة إلى الرمز ذي الصلة، إلى الملفات التي تم إنشاؤها في المشروع.

الخطوة 2: إنشاء تخطيط العنصر باستخدام ربط البيانات

  1. فتح "SleepNightAdapter.kt"
  2. في الفئة ViewHolder، ابحث عن الطريقة from().
  3. احذف تعريف المتغيّر view.

الرمز المراد حذفه:

val view = layoutInflater
       .inflate(R.layout.list_item_sleep_night, parent, false)
  1. في المكان الذي كان فيه المتغيّر view، حدِّد متغيّرًا جديدًا باسم binding يعمل على تضخيم عنصر الربط ListItemSleepNightBinding، كما هو موضّح أدناه. استورِد العنصر الرابط المطلوب.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
  1. في نهاية الدالة، بدلاً من عرض view، اعرض binding.
return ViewHolder(binding)
  1. للتخلص من الخطأ، ضَع مؤشر الماوس على الكلمة binding. اضغط على Alt+Enter (Option+Enter على جهاز Mac) لفتح قائمة "النية".
  1. اختَر تغيير نوع المَعلمة itemView لدالة الإنشاء الأساسية للفئة ViewHolder إلى ListItemSleepNightBinding. يؤدي ذلك إلى تعديل نوع المَعلمة للفئة ViewHolder.

  1. انتقِل للأعلى إلى تعريف الفئة ViewHolder للاطّلاع على التغيير في التوقيع. يظهر لك خطأ في itemView، لأنّك غيّرت itemView إلى binding في الطريقة from().

    في تعريف الفئة ViewHolder، انقر بزر الماوس الأيمن على أحد مواضع itemView واختَر Refactor (إعادة تصميم) > Rename (إعادة تسمية). غيِّر الاسم إلى binding.
  2. أضِف البادئة val إلى مَعلمة الدالة الإنشائية binding لجعلها سمة.
  3. في استدعاء الفئة الرئيسية، RecyclerView.ViewHolder، غيِّر المَعلمة من binding إلى binding.root. يجب تمرير View، وbinding.root هو ConstraintLayout الجذر في تخطيط العنصر.
  4. يجب أن يبدو تعريف الفئة المكتمل على النحو الموضّح في الرمز البرمجي أدناه.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){

يظهر لك أيضًا خطأ في طلبات findViewById()، وعليك إصلاح هذا الخطأ أولاً.

الخطوة 3: استبدال findViewById()

يمكنك الآن تعديل السمات sleepLength وquality وqualityImage لاستخدام العنصر binding بدلاً من findViewById().

  1. غيِّر عمليات التهيئة الخاصة بـ sleepLength وqualityString وqualityImage لاستخدام طرق العرض الخاصة بالكائن binding، كما هو موضّح أدناه. بعد ذلك، من المفترض ألّا يعرض الرمز أي أخطاء أخرى.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage

بعد وضع عنصر الربط، لن تحتاج إلى تحديد السمات sleepLength وquality وqualityImage على الإطلاق. سيخزّن DataBinding عمليات البحث مؤقتًا، لذا ليس من الضروري تعريف هذه الخصائص.

  1. انقر بزر الماوس الأيمن على أسماء المواقع sleepLength وquality وqualityImage. اختَر إعادة تصميم > تضمين، أو اضغط على Control+Command+N (Option+Command+N على جهاز Mac).
  2. شغِّل تطبيقك. (قد تحتاج إلى تنظيف مشروعك وإعادة إنشائه إذا كان يتضمّن أخطاء).

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

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

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

الخطوة 1: إنشاء أدوات ربط البيانات

يُرجى العِلم أنّه عليك استيراد عدد من الصفوف في هذه الخطوة، ولن يتم تحديدها بشكل فردي.

  1. فتح "SleepNightAdapater.kt"
  2. داخل الفئة ViewHolder، ابحث عن الطريقة bind() وذكِّر نفسك بما تفعله هذه الطريقة. ستأخذ الرمز الذي يحتسب قيم binding.sleepLength وbinding.quality وbinding.qualityImage، وتستخدمه داخل المحوّل بدلاً من ذلك. (في الوقت الحالي، اترك الرمز كما هو، وسيتم نقله في خطوة لاحقة).
  3. في حزمة sleeptracker، أنشئ ملفًا باسم BindingUtils.kt وافتحه.
  4. عرِّف دالة إضافة على TextView باسم setSleepDurationFormatted، ومرِّر SleepNight. ستكون هذه الدالة هي المحوّل الخاص بك لاحتساب مدة النوم وتنسيقها.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
  1. في نص setSleepDurationFormatted، اربط البيانات بطريقة العرض كما فعلت في ViewHolder.bind(). استدعِ convertDurationToFormatted()، ثم اضبط text الخاص بـ TextView على النص المنسَّق. (بما أنّ هذه دالة إضافية في TextView، يمكنك الوصول مباشرةً إلى السمة text).
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
  1. لإعلام ميزة ربط البيانات بمحوّل الربط هذا، أضِف التعليق التوضيحي @BindingAdapter إلى الدالة.
  2. هذه الدالة هي أداة الربط للسمة sleepDurationFormatted، لذا مرِّر sleepDurationFormatted كوسيطة إلى @BindingAdapter.
@BindingAdapter("sleepDurationFormatted")
  1. يضبط المحوّل الثاني جودة النوم استنادًا إلى القيمة في العنصر SleepNight. أنشئ دالة إضافة باسم setSleepQualityString() في TextView، وأدخِل SleepNight.
  2. في النص الأساسي، اربط البيانات بطريقة العرض كما فعلت في ViewHolder.bind(). اتّصِل بالرقم convertNumericQualityToString واضبط text.
  3. أضِف التعليق التوضيحي @BindingAdapter("sleepQualityString") إلى الدالة.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
   text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
  1. يضبط محوّل ربط البيانات الثالث الصورة في عرض الصورة. أنشئ دالة الإضافة على ImageView، واستدعِ setSleepImage، واستخدِم الرمز من ViewHolder.bind()، كما هو موضّح أدناه.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
   setImageResource(when (item.sleepQuality) {
       0 -> R.drawable.ic_sleep_0
       1 -> R.drawable.ic_sleep_1
       2 -> R.drawable.ic_sleep_2
       3 -> R.drawable.ic_sleep_3
       4 -> R.drawable.ic_sleep_4
       5 -> R.drawable.ic_sleep_5
       else -> R.drawable.ic_sleep_active
   })
}

الخطوة 2: تعديل SleepNightAdapter

  1. فتح "SleepNightAdapter.kt"
  2. احذف كل شيء في الطريقة bind()، لأنّه يمكنك الآن استخدام ربط البيانات والمحوّلات الجديدة لإنجاز هذا العمل نيابةً عنك.
fun bind(item: SleepNight) {
}
  1. داخل bind()، عليك تعيين قيمة item للنوم، لأنّك بحاجة إلى إخبار عنصر الربط بشأن SleepNight الجديد.
binding.sleep = item
  1. أسفل هذا السطر، أضِف binding.executePendingBindings(). هذه الدالة هي عملية تحسين تطلب من ميزة ربط البيانات تنفيذ أي عمليات ربط معلّقة على الفور. من المستحسن دائمًا استدعاء executePendingBindings() عند استخدام أدوات ربط البيانات في RecyclerView، لأنّ ذلك قد يؤدي إلى تسريع عملية تحديد حجم طرق العرض قليلاً.
 binding.executePendingBindings()

الخطوة 3: إضافة عمليات الربط إلى تنسيق XML

  1. فتح "list_item_sleep_night.xml"
  2. في ImageView، أضِف السمة app بالاسم نفسه لبرنامج ربط البيانات الذي يضبط الصورة. مرِّر المتغيّر sleep، كما هو موضّح أدناه.

    ينشئ هذا الموقع الرابط بين طريقة العرض وعنصر الربط من خلال المحوّل. عندما تتم الإشارة إلى sleepImage، سيعدّل المحوّل البيانات من SleepNight.
app:sleepImage="@{sleep}"
  1. كرِّر الخطوات نفسها مع طرق عرض النص sleep_length وquality_string. عند الإشارة إلى sleepDurationFormatted أو sleepQualityString، ستعدّل المحوّلات البيانات من SleepNight.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
  1. شغِّل تطبيقك، وسيعمل بالطريقة نفسها التي كان يعمل بها من قبل. تتولّى أدوات ربط البيانات جميع مهام التنسيق وتعديل طرق العرض عند تغيُّر البيانات، ما يؤدي إلى تبسيط ViewHolder ومنح الرمز البرمجي بنية أفضل بكثير من ذي قبل.

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

تهانينا! في هذه المرحلة، تكون قد قطعت شوطًا كبيرًا نحو إتقان RecyclerView على Android.

مشروع استوديو Android: RecyclerViewDiffUtilDataBinding

DiffUtil:

  • يحتوي RecyclerView على فئة تُسمى DiffUtil، وهي مخصّصة لاحتساب الفروق بين قائمتَين.
  • يحتوي DiffUtil على فئة باسم ItemCallBack يمكنك توسيعها لمعرفة الفرق بين قائمتَين.
  • في الفئة ItemCallback، يجب إلغاء الطريقتَين areItemsTheSame() وareContentsTheSame().

ListAdapter:

  • للحصول على بعض ميزات إدارة القوائم مجانًا، يمكنك استخدام الفئة ListAdapter بدلاً من RecyclerView.Adapter. ومع ذلك، إذا كنت تستخدم ListAdapter، عليك كتابة محوّل خاص بك للتصميمات الأخرى، ولهذا السبب يوضّح لك هذا الدرس التطبيقي كيفية إجراء ذلك.
  • لفتح قائمة الإجراءات المقترَحة في "استوديو Android"، ضَع المؤشر على أي عنصر من عناصر الرمز واضغط على Alt+Enter (Option+Enter على جهاز Mac). تكون هذه القائمة مفيدة بشكل خاص لإعادة تصميم الرمز البرمجي وإنشاء نماذج أولية لتنفيذ الطرق. القائمة حساسة للسياق، لذا عليك وضع المؤشر في المكان الصحيح تمامًا للحصول على القائمة الصحيحة.

ربط البيانات:

  • استخدِم ربط البيانات في تخطيط العنصر لربط البيانات بطرق العرض.

محولات الربط:

  • كنت تستخدم Transformations سابقًا لإنشاء سلاسل من البيانات. إذا كنت بحاجة إلى ربط بيانات من أنواع مختلفة أو معقّدة، قدِّم أدوات ربط البيانات للمساعدة في استخدامها.
  • لتعريف أداة ربط، حدِّد طريقة تتضمّن عنصرًا وطريقة عرض، وأضِف تعليقًا توضيحيًا إلى الطريقة باستخدام @BindingAdapter. في Kotlin، يمكنك كتابة أداة ربط البيانات كدالة إضافية في View. مرِّر اسم السمة التي يكيّفها المحوّل. على سبيل المثال:
@BindingAdapter("sleepDurationFormatted")
  • في تنسيق XML، اضبط السمة app بالاسم نفسه لبرنامج ربط البيانات. مرِّر متغيّرًا يتضمّن البيانات. على سبيل المثال:
.app:sleepDurationFormatted="@{sleep}"

دورات Udacity التدريبية:

مستندات مطوّري تطبيقات Android:

مراجع أخرى:

يسرد هذا القسم مهامًا منزلية محتملة للطلاب الذين يعملون على هذا الدرس التطبيقي العملي كجزء من دورة تدريبية يقودها مدرّب. على المعلّم تنفيذ ما يلي:

  • حدِّد واجبًا منزليًا إذا لزم الأمر.
  • توضيح كيفية إرسال الواجبات المنزلية للطلاب
  • وضع درجات للواجبات المنزلية

يمكن للمدرّبين استخدام هذه الاقتراحات بالقدر الذي يريدونه، ويجب ألا يترددوا في تكليف الطلاب بأي واجبات منزلية أخرى يرونها مناسبة.

إذا كنت تعمل على هذا الدرس العملي بنفسك، يمكنك استخدام مهام الواجب المنزلي هذه لاختبار معلوماتك.

الإجابة عن هذه الأسئلة

السؤال 1

أيّ مما يلي ضروري لاستخدام DiffUtil؟ يُرجى اختيار جميع الإجابات المناسبة.

▢ وسِّع نطاق الفئة ItemCallBack.

▢ إلغاء areItemsTheSame()

▢ إلغاء areContentsTheSame()

‫▢ استخدِم ربط البيانات لتتبُّع الاختلافات بين العناصر.

السؤال 2

أيّ مما يلي ينطبق على أدوات ربط البيانات؟

▢ محوّل الربط هو دالة تمّت إضافة التعليق التوضيحي @BindingAdapter إليها.

‫▢ يتيح لك استخدام أداة ربط البيانات فصل تنسيق البيانات عن حاوية العرض.

▢ يجب استخدام RecyclerViewAdapter إذا كنت تريد استخدام أدوات ربط البيانات.

‫▢ Binding adapters هي حلّ جيد عندما تحتاج إلى تحويل بيانات معقّدة.

السؤال 3

متى يجب استخدام Transformations بدلاً من أداة ربط البيانات؟ يُرجى اختيار جميع الإجابات المناسبة.

▢ بياناتك بسيطة.

▢ أنت بصدد تنسيق سلسلة.

▢ قائمتك طويلة جدًا.

▢ لا يحتوي ViewHolder إلا على عرض واحد.

ابدأ الدرس التالي: 7.3: GridLayout مع RecyclerView