يشكّل هذا الدرس التطبيقي جزءًا من الدورة التدريبية لأساسيات 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.
- إذا لزم الأمر، يمكنك تنزيل تطبيق RecyclerViewDiffUtilDataBinding-Starter من GitHub وفتح المشروع في "استوديو Android".
- شغِّل التطبيق.
- افتح ملف
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) واختَر تنفيذ الأعضاء. - في مربع الحوار الذي يظهر، انقر بزر الماوس الأيمن على
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.
}
- داخل
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: تغيير المحوّل لتمديد ListLister
- في الملف
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: استخدام SendList() للحفاظ على تحديث القائمة
يجب أن يبلِغ رمزك 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)
- في نهاية الدالة، يمكنك إرجاع
binding
بدلاً من عرضview
.
return ViewHolder(binding)
- للتخلص من الخطأ، ضع المؤشر على الكلمة
binding
. اضغط علىAlt+Enter
(Option+Enter
على جهاز Mac) لفتح قائمة الأهداف.
- اختر تغيير المعلمة 'itemView' نوع المُنشئ الأساسي للصف 'Viewholder' to 'ListItemSleepNightBinding'. يؤدي ذلك إلى تعديل نوع المعلّمة للفئة
ViewHolder
.
- مرِّر للأعلى وصولاً إلى تعريف فئة
ViewHolder
للاطّلاع على التغيير في التوقيع. يظهر لك خطأitemView
، وذلك لأنك غيّرتitemView
إلىbinding
في طريقةfrom()
.
في تعريف الفئةViewHolder
، انقر بزر الماوس الأيمن على أحد مواضع ورودitemView
واختَر ReACTOR > إعادة تسمية. غيِّر الاسم إلىbinding
. - يجب أن تبدأ معلمة المُنشئ "
binding
" بـval
لجعلها خاصية. - في الاستدعاء للصف الرئيسي،
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
. اختَر ReACTOR > Inline أو اضغط على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: تعديل SleepNightAdaptiveer
- فتح
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
، ستضطر إلى كتابة المحوّل الخاص بك لتنسيقات أخرى، ولهذا السبب يوضّح لك هذا الدرس التطبيقي كيفية تنفيذ ذلك. - لفتح قائمة intent في Android Studio، ضع المؤشر على أي عنصر من الرموز واضغط على
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
إذا كنت تريد استخدام محوّلات الربط.
▢ المحولات المُلزمة هي حل جيد عندما تحتاج إلى تحويل بيانات معقدة.
السؤال 3
متى يمكنك استخدام Transformations
بدلاً من محوّل ربط؟ يُرجى اختيار كل الإجابات المناسبة.
▢ بياناتك بسيطة.
▢ أنت بصدد تنسيق سلسلة.
▢ قائمتك طويلة جدًا.
▢ تحتوي ViewHolder
على ملف شخصي واحد فقط.
بدء الدرس التالي: