هذا الدرس التطبيقي حول الترميز هو جزء من دورة "أساسيات 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.
- إذا لزم الأمر، نزِّل تطبيق RecyclerViewDiffUtilDataBinding-Starter من GitHub وافتح المشروع في Android Studio.
- شغِّل التطبيق.
- افتح ملف
SleepNightAdapter.kt
. - افحص الرمز البرمجي للتعرّف على بنية التطبيق. راجِع الرسم البياني أدناه للحصول على ملخّص حول استخدام
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
.
- فتح "
SleepNightAdapter.kt
" - أسفل تعريف الفئة الكامل لـ
SleepNightAdapter
، أنشئ فئة جديدة ذات مستوى أعلى باسمSleepNightDiffCallback
تتضمّنDiffUtil.ItemCallback
. مرِّرSleepNight
كمعلَمة عامة.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- ضَع المؤشر في اسم الفئة
SleepNightDiffCallback
. - اضغط على
Alt+Enter
(Option+Enter
على جهاز Mac) واختَر تنفيذ الأعضاء. - في مربّع الحوار الذي يظهر، اضغط على 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.
}
- داخل
areItemsTheSame()
، استبدِلTODO
بالرمز الذي يختبر ما إذا كان العنصرانSleepNight
اللذان تم تمريرهما،oldItem
وnewItem
، متطابقَين. إذا كانت العناصر تتضمّنnightId
نفسه، تكون هي نفسها، لذا يجب عرضtrue
. بخلاف ذلك، أعِدfalse
. تستخدمDiffUtil
هذا الاختبار للمساعدة في معرفة ما إذا تمت إضافة عنصر أو إزالته أو نقله.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- داخل
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
- في الملف
SleepNightAdapter.kt
، غيِّر توقيع الفئةSleepNightAdapter
لتوسيعListAdapter
. - إذا طُلب منك ذلك، استورِد
androidx.recyclerview.widget.ListAdapter
. - أضِف
SleepNight
كمعلَمة أولى إلىListAdapter
، قبلSleepNightAdapter.ViewHolder
. - أضِف
SleepNightDiffCallback()
كمَعلمة إلى الدالة الإنشائية. سيستخدمListAdapter
هذا لتحديد التغييرات التي تم إجراؤها في القائمة. يجب أن تبدو توقيعات فئةSleepNightAdapter
المكتملة كما هو موضّح أدناه.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- داخل فئة
SleepNightAdapter
، احذف الحقلdata
، بما في ذلك الدالة الضابطة. لن تحتاج إليها بعد الآن، لأنّListAdapter
يتتبّع القائمة نيابةً عنك. - احذف عملية الإلغاء الخاصة بـ
getItemCount()
، لأنّListAdapter
تنفّذ هذه الطريقة نيابةً عنك. - للتخلّص من الخطأ في
onBindViewHolder()
، غيِّر المتغيّرitem
. بدلاً من استخدامdata
للحصول علىitem
، استدعِ طريقةgetItem(position)
التي يوفّرهاListAdapter
.
val item = getItem(position)
الخطوة 2: استخدام submitList() لإبقاء القائمة محدَّثة
يجب أن يوضّح الرمز البرمجي ListAdapter
أنّه تتوفّر قائمة معدَّلة. توفّر ListAdapter
طريقة تُسمى submitList()
لإعلام ListAdapter
بأنّه يتوفّر إصدار جديد من القائمة. عند استدعاء هذه الطريقة، تقارن ListAdapter
القائمة الجديدة بالقائمة القديمة وترصد العناصر التي تمت إضافتها أو إزالتها أو نقلها أو تغييرها. بعد ذلك، ListAdapter
تعدّل السلع المعروضة من خلال RecyclerView
.
- فتح "
SleepTrackerFragment.kt
" - في
onCreateView()
، في أداة المراقبة علىsleepTrackerViewModel
، ابحث عن الخطأ الذي تتم فيه الإشارة إلى المتغيّرdata
الذي حذفْته. - استبدِل
adapter.data = it
بمكالمة إلىadapter.submitList(it)
. يظهر الرمز المعدَّل أدناه.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- شغِّل تطبيقك، وسيتم تشغيله بشكل أسرع، ولكن قد لا يكون ذلك ملحوظًا إذا كانت قائمتك صغيرة.
في هذه المهمة، ستستخدم الأسلوب نفسه المستخدَم في دروس البرمجة السابقة لإعداد ربط البيانات، وستتخلّص من طلبات findViewById()
.
الخطوة 1: إضافة ربط البيانات إلى ملف التنسيق
- افتح ملف التنسيق
list_item_sleep_night.xml
في علامة التبويب نص. - ضَع المؤشر على العلامة
ConstraintLayout
واضغط علىAlt+Enter
(Option+Enter
على جهاز Mac). يتم فتح قائمة الإجراءات المقصودة (قائمة "الإصلاح السريع"). - اختَر التحويل إلى تنسيق ربط البيانات. يؤدي ذلك إلى تضمين التنسيق في
<layout>
وإضافة علامة<data>
في الداخل. - ارجع إلى أعلى الصفحة، إذا لزم الأمر، وفي علامة
<data>
، عرِّف متغيّرًا باسمsleep
. - اجعل
type
هو الاسم المؤهّل بالكامل لـSleepNight
،com.example.android.trackmysleepquality.database.SleepNight
. يجب أن تبدو علامة<data>
المكتملة كما هو موضّح أدناه.
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- لفرض إنشاء العنصر
Binding
، اختَر إنشاء > تنظيف المشروع، ثم اختَر إنشاء > إعادة إنشاء المشروع. (إذا كنت لا تزال تواجه مشاكل، اختَر ملف > إبطال ذاكرات التخزين المؤقت / إعادة التشغيل). تتم إضافة عنصر الربطListItemSleepNightBinding
، بالإضافة إلى الرمز ذي الصلة، إلى الملفات التي تم إنشاؤها في المشروع.
الخطوة 2: إنشاء تخطيط العنصر باستخدام ربط البيانات
- فتح "
SleepNightAdapter.kt
" - في الفئة
ViewHolder
، ابحث عن الطريقةfrom()
. - احذف تعريف المتغيّر
view
.
الرمز المراد حذفه:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- في المكان الذي كان فيه المتغيّر
view
، حدِّد متغيّرًا جديدًا باسمbinding
يعمل على تضخيم عنصر الربطListItemSleepNightBinding
، كما هو موضّح أدناه. استورِد العنصر الرابط المطلوب.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- في نهاية الدالة، بدلاً من عرض
view
، اعرضbinding
.
return ViewHolder(binding)
- للتخلص من الخطأ، ضَع مؤشر الماوس على الكلمة
binding
. اضغط علىAlt+Enter
(Option+Enter
على جهاز Mac) لفتح قائمة "النية".
- اختَر تغيير نوع المَعلمة itemView لدالة الإنشاء الأساسية للفئة ViewHolder إلى ListItemSleepNightBinding. يؤدي ذلك إلى تعديل نوع المَعلمة للفئة
ViewHolder
.
- انتقِل للأعلى إلى تعريف الفئة
ViewHolder
للاطّلاع على التغيير في التوقيع. يظهر لك خطأ فيitemView
، لأنّك غيّرتitemView
إلىbinding
في الطريقةfrom()
.
في تعريف الفئةViewHolder
، انقر بزر الماوس الأيمن على أحد مواضعitemView
واختَر Refactor (إعادة تصميم) > Rename (إعادة تسمية). غيِّر الاسم إلىbinding
. - أضِف البادئة
val
إلى مَعلمة الدالة الإنشائيةbinding
لجعلها سمة. - في استدعاء الفئة الرئيسية،
RecyclerView.ViewHolder
، غيِّر المَعلمة منbinding
إلىbinding.root
. يجب تمريرView
، وbinding.root
هوConstraintLayout
الجذر في تخطيط العنصر. - يجب أن يبدو تعريف الفئة المكتمل على النحو الموضّح في الرمز البرمجي أدناه.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
يظهر لك أيضًا خطأ في طلبات findViewById()
، وعليك إصلاح هذا الخطأ أولاً.
الخطوة 3: استبدال findViewById()
يمكنك الآن تعديل السمات sleepLength
وquality
وqualityImage
لاستخدام العنصر binding
بدلاً من findViewById()
.
- غيِّر عمليات التهيئة الخاصة بـ
sleepLength
وqualityString
وqualityImage
لاستخدام طرق العرض الخاصة بالكائنbinding
، كما هو موضّح أدناه. بعد ذلك، من المفترض ألّا يعرض الرمز أي أخطاء أخرى.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
بعد وضع عنصر الربط، لن تحتاج إلى تحديد السمات sleepLength
وquality
وqualityImage
على الإطلاق. سيخزّن DataBinding
عمليات البحث مؤقتًا، لذا ليس من الضروري تعريف هذه الخصائص.
- انقر بزر الماوس الأيمن على أسماء المواقع
sleepLength
وquality
وqualityImage
. اختَر إعادة تصميم > تضمين، أو اضغط علىControl+Command+N
(Option+Command+N
على جهاز Mac). - شغِّل تطبيقك. (قد تحتاج إلى تنظيف مشروعك وإعادة إنشائه إذا كان يتضمّن أخطاء).
في هذه المهمة، ستعمل على ترقية تطبيقك لاستخدام ربط البيانات مع أدوات ربط لتحديد البيانات في طرق العرض.
في درس برمجة سابق، استخدمت الفئة Transformations
للحصول على LiveData
وإنشاء سلاسل منسَّقة لعرضها في طرق عرض النصوص. ومع ذلك، إذا كنت بحاجة إلى ربط أنواع مختلفة أو أنواع معقّدة، يمكنك توفير أدوات ربط لتساعد ميزة "ربط البيانات" في استخدام هذه الأنواع. محوّلات الربط هي محوّلات تأخذ بياناتك وتكيّفها لتصبح شيئًا يمكن لربط البيانات استخدامه لربط طريقة عرض، مثل نص أو صورة.
ستنفّذ ثلاثة برامج ربط، واحد للصورة عالية الجودة، وواحد لكل حقل نصي. باختصار، لتحديد أداة ربط، عليك تحديد طريقة تأخذ عنصرًا وعرضًا، وإضافة التعليق التوضيحي @BindingAdapter
إليها. في نص الدالة، يمكنك تنفيذ عملية التحويل. في Kotlin، يمكنك كتابة أداة ربط كدالة إضافة في فئة العرض التي تتلقّى البيانات.
الخطوة 1: إنشاء أدوات ربط البيانات
يُرجى العِلم أنّه عليك استيراد عدد من الصفوف في هذه الخطوة، ولن يتم تحديدها بشكل فردي.
- فتح "
SleepNightAdapater.kt
" - داخل الفئة
ViewHolder
، ابحث عن الطريقةbind()
وذكِّر نفسك بما تفعله هذه الطريقة. ستأخذ الرمز الذي يحتسب قيمbinding.sleepLength
وbinding.quality
وbinding.qualityImage
، وتستخدمه داخل المحوّل بدلاً من ذلك. (في الوقت الحالي، اترك الرمز كما هو، وسيتم نقله في خطوة لاحقة). - في حزمة
sleeptracker
، أنشئ ملفًا باسمBindingUtils.kt
وافتحه. - عرِّف دالة إضافة على
TextView
باسمsetSleepDurationFormatted
، ومرِّرSleepNight
. ستكون هذه الدالة هي المحوّل الخاص بك لاحتساب مدة النوم وتنسيقها.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- في نص
setSleepDurationFormatted
، اربط البيانات بطريقة العرض كما فعلت فيViewHolder.bind()
. استدعِconvertDurationToFormatted()
، ثم اضبطtext
الخاص بـTextView
على النص المنسَّق. (بما أنّ هذه دالة إضافية فيTextView
، يمكنك الوصول مباشرةً إلى السمةtext
).
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- لإعلام ميزة ربط البيانات بمحوّل الربط هذا، أضِف التعليق التوضيحي
@BindingAdapter
إلى الدالة. - هذه الدالة هي أداة الربط للسمة
sleepDurationFormatted
، لذا مرِّرsleepDurationFormatted
كوسيطة إلى@BindingAdapter
.
@BindingAdapter("sleepDurationFormatted")
- يضبط المحوّل الثاني جودة النوم استنادًا إلى القيمة في العنصر
SleepNight
. أنشئ دالة إضافة باسمsetSleepQualityString()
فيTextView
، وأدخِلSleepNight
. - في النص الأساسي، اربط البيانات بطريقة العرض كما فعلت في
ViewHolder.bind()
. اتّصِل بالرقمconvertNumericQualityToString
واضبطtext
. - أضِف التعليق التوضيحي
@BindingAdapter("sleepQualityString")
إلى الدالة.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- يضبط محوّل ربط البيانات الثالث الصورة في عرض الصورة. أنشئ دالة الإضافة على
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
- فتح "
SleepNightAdapter.kt
" - احذف كل شيء في الطريقة
bind()
، لأنّه يمكنك الآن استخدام ربط البيانات والمحوّلات الجديدة لإنجاز هذا العمل نيابةً عنك.
fun bind(item: SleepNight) {
}
- داخل
bind()
، عليك تعيين قيمةitem
للنوم، لأنّك بحاجة إلى إخبار عنصر الربط بشأنSleepNight
الجديد.
binding.sleep = item
- أسفل هذا السطر، أضِف
binding.executePendingBindings()
. هذه الدالة هي عملية تحسين تطلب من ميزة ربط البيانات تنفيذ أي عمليات ربط معلّقة على الفور. من المستحسن دائمًا استدعاءexecutePendingBindings()
عند استخدام أدوات ربط البيانات فيRecyclerView
، لأنّ ذلك قد يؤدي إلى تسريع عملية تحديد حجم طرق العرض قليلاً.
binding.executePendingBindings()
الخطوة 3: إضافة عمليات الربط إلى تنسيق XML
- فتح "
list_item_sleep_night.xml
" - في
ImageView
، أضِف السمةapp
بالاسم نفسه لبرنامج ربط البيانات الذي يضبط الصورة. مرِّر المتغيّرsleep
، كما هو موضّح أدناه.
ينشئ هذا الموقع الرابط بين طريقة العرض وعنصر الربط من خلال المحوّل. عندما تتم الإشارة إلىsleepImage
، سيعدّل المحوّل البيانات منSleepNight
.
app:sleepImage="@{sleep}"
- كرِّر الخطوات نفسها مع طرق عرض النص
sleep_length
وquality_string
. عند الإشارة إلىsleepDurationFormatted
أوsleepQualityString
، ستعدّل المحوّلات البيانات منSleepNight
.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- شغِّل تطبيقك، وسيعمل بالطريقة نفسها التي كان يعمل بها من قبل. تتولّى أدوات ربط البيانات جميع مهام التنسيق وتعديل طرق العرض عند تغيُّر البيانات، ما يؤدي إلى تبسيط
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:
- إنشاء قائمة باستخدام RecyclerView
RecyclerView
DiffUtil
- مكتبة ربط البيانات
- برامج ربط البيانات
notifyDataSetChanged()
Transformations
مراجع أخرى:
يسرد هذا القسم مهامًا منزلية محتملة للطلاب الذين يعملون على هذا الدرس التطبيقي العملي كجزء من دورة تدريبية يقودها مدرّب. على المعلّم تنفيذ ما يلي:
- حدِّد واجبًا منزليًا إذا لزم الأمر.
- توضيح كيفية إرسال الواجبات المنزلية للطلاب
- وضع درجات للواجبات المنزلية
يمكن للمدرّبين استخدام هذه الاقتراحات بالقدر الذي يريدونه، ويجب ألا يترددوا في تكليف الطلاب بأي واجبات منزلية أخرى يرونها مناسبة.
إذا كنت تعمل على هذا الدرس العملي بنفسك، يمكنك استخدام مهام الواجب المنزلي هذه لاختبار معلوماتك.
الإجابة عن هذه الأسئلة
السؤال 1
أيّ مما يلي ضروري لاستخدام DiffUtil
؟ يُرجى اختيار جميع الإجابات المناسبة.
▢ وسِّع نطاق الفئة ItemCallBack
.
▢ إلغاء areItemsTheSame()
▢ إلغاء areContentsTheSame()
▢ استخدِم ربط البيانات لتتبُّع الاختلافات بين العناصر.
السؤال 2
أيّ مما يلي ينطبق على أدوات ربط البيانات؟
▢ محوّل الربط هو دالة تمّت إضافة التعليق التوضيحي @BindingAdapter
إليها.
▢ يتيح لك استخدام أداة ربط البيانات فصل تنسيق البيانات عن حاوية العرض.
▢ يجب استخدام RecyclerViewAdapter
إذا كنت تريد استخدام أدوات ربط البيانات.
▢ Binding adapters هي حلّ جيد عندما تحتاج إلى تحويل بيانات معقّدة.
السؤال 3
متى يجب استخدام Transformations
بدلاً من أداة ربط البيانات؟ يُرجى اختيار جميع الإجابات المناسبة.
▢ بياناتك بسيطة.
▢ أنت بصدد تنسيق سلسلة.
▢ قائمتك طويلة جدًا.
▢ لا يحتوي ViewHolder
إلا على عرض واحد.
ابدأ الدرس التالي: