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

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

مقدمة

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

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

ما يجب معرفته

  • إنشاء واجهة مستخدم أساسية باستخدام النشاط والأجزاء والمشاهدات.
  • التنقّل بين الأجزاء واستخدام safeArgs لتمرير البيانات بين الأجزاء
  • عرض النماذج وعرض مصانع النماذج والتحوّلات وLiveData ومراصدها.
  • كيفية إنشاء قاعدة بيانات Room وإنشاء داود والتعريف بالكيانات
  • كيفية استخدام الكوروتينات في قاعدة البيانات والمهام الأخرى الطويلة الأمد
  • كيفية تنفيذ 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".
  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. في مربع الحوار الذي يظهر، انقر بزر الماوس الأيمن على areItemsTheSame() لاختيار طريقتَي 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: تغيير المحوّل لتمديد ListLister

  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: استخدام SendList() للحفاظ على تحديث القائمة

يجب أن يبلِغ رمزك 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، اختَر إنشاء &gt؛ مشروع نظيف، ثم اختَر إنشاء &gt؛ إعادة إنشاء مشروع. (إذا كنت لا تزال تواجه مشاكل، اختَر الملف &gt؛ إلغاء صلاحية ذاكرة التخزين المؤقت/إعادة التشغيل.) تتم إضافة العنصر المُلزِم 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. في نهاية الدالة، يمكنك إرجاع binding بدلاً من عرض view.
return ViewHolder(binding)
  1. للتخلص من الخطأ، ضع المؤشر على الكلمة binding. اضغط على Alt+Enter (Option+Enter على جهاز Mac) لفتح قائمة الأهداف.
  1. اختر تغيير المعلمة 'itemView' نوع المُنشئ الأساسي للصف 'Viewholder' to 'ListItemSleepNightBinding'. يؤدي ذلك إلى تعديل نوع المعلّمة للفئة ViewHolder.

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

    في تعريف الفئة ViewHolder، انقر بزر الماوس الأيمن على أحد مواضع ورود itemView واختَر ReACTOR > إعادة تسمية. غيِّر الاسم إلى binding.
  2. يجب أن تبدأ معلمة المُنشئ "binding" بـ val لجعلها خاصية.
  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. اختَر ReACTOR > Inline أو اضغط على 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: تعديل SleepNightAdaptiveer

  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، ستضطر إلى كتابة المحوّل الخاص بك لتنسيقات أخرى، ولهذا السبب يوضّح لك هذا الدرس التطبيقي كيفية تنفيذ ذلك.
  • لفتح قائمة intent في Android Studio، ضع المؤشر على أي عنصر من الرموز واضغط على 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 إذا كنت تريد استخدام محوّلات الربط.

▢ المحولات المُلزمة هي حل جيد عندما تحتاج إلى تحويل بيانات معقدة.

السؤال 3

متى يمكنك استخدام Transformations بدلاً من محوّل ربط؟ يُرجى اختيار كل الإجابات المناسبة.

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

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

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

▢ تحتوي ViewHolder على ملف شخصي واحد فقط.

بدء الدرس التالي: 7.3: GridLayout with RecyclerView