ה-codelab הזה הוא חלק מהקורס Android Kotlin Fundamentals. כדי להפיק את המרב מהקורס הזה, מומלץ לעבוד על ה-codelabs לפי הסדר. כל ה-codelab של הקורס מפורטים בדף הנחיתה של ה-codelab בנושא יסודות Kotlin ל-Android.
מבוא
במדריך הקודם, עדכנתם את האפליקציה TrackMySleepQuality כדי להציג נתונים על איכות השינה ב-RecyclerView
. הטכניקות שלמדתם כשבניתם את RecyclerView
הראשון שלכם מספיקות לרוב RecyclerViews
שמציגים רשימות פשוטות שלא גדולות מדי. עם זאת, יש מספר טכניקות שבעזרתן אפשר להשתמש ב-RecyclerView
בצורה יעילה יותר ברשימות גדולות, ולשמור על קוד קל לתחזוקה ולהרחבה ברשימות ובטבלאות מורכבות.
ב-codelab הזה, תמשיכו לפתח את אפליקציית מעקב השינה מה-codelab הקודם. תלמדו דרך יעילה יותר לעדכן את רשימת נתוני השינה, ותלמדו איך להשתמש בקישור נתונים עם RecyclerView
. (אם אין לכם את האפליקציה מה-codelab הקודם, אתם יכולים להוריד קוד התחלתי ל-codelab הזה).
מה שכדאי לדעת
- בניית ממשק משתמש בסיסי באמצעות פעילות, רכיבי Fragment ותצוגות.
- ניווט בין פרגמנטים ושימוש ב-
safeArgs
כדי להעביר נתונים בין פרגמנטים. - אפשר לראות את המודלים, את מפעלי המודלים, את הטרנספורמציות ואת
LiveData
ואת האובזרברים שלהם. - איך יוצרים מסד נתונים של
Room
, יוצרים DAO ומגדירים ישויות. - איך משתמשים ב-coroutines למסד נתונים ולמשימות אחרות שפועלות לאורך זמן.
- איך מטמיעים
RecyclerView
בסיסי עםAdapter
,ViewHolder
ופריסת פריטים.
מה תלמדו
- איך משתמשים ב-
DiffUtil
כדי לעדכן ביעילות רשימה שמוצגת על ידיRecyclerView
. - איך משתמשים בקישור נתונים עם
RecyclerView
- איך משתמשים במתאמי קישור כדי לשנות נתונים.
הפעולות שתבצעו:
- המשך פיתוח של אפליקציית TrackMySleepQuality מתוך ה-codelab הקודם בסדרה הזו.
- כדי לעדכן את הרשימה ביעילות באמצעות
DiffUtil
, צריך לעדכן אתSleepNightAdapter
. - מטמיעים קשירת נתונים עבור
RecyclerView
באמצעות מתאמי קשירה כדי לבצע טרנספורמציה של הנתונים.
לאפליקציה למעקב אחרי שינה יש שני מסכים, שמיוצגים על ידי פרגמנטים, כמו שמוצג באיור שלמטה.
במסך הראשון, שמוצג בצד ימין, יש לחצנים להפעלה ולהפסקה של המעקב. במסך מוצגים חלק מנתוני השינה של המשתמש. הלחצן ניקוי מוחק באופן סופי את כל הנתונים שהאפליקציה אספה על המשתמש. במסך השני, שמוצג בצד שמאל, בוחרים את דירוג איכות השינה.
האפליקציה הזו מתוכננת להשתמש בבקר ממשק משתמש, ב-ViewModel
וב-LiveData
, ובמסד נתונים של Room
כדי לשמור את נתוני השינה.
נתוני השינה מוצגים בRecyclerView
. ב-codelab הזה, תבנו את החלק DiffUtil
ואת החלק של קישור הנתונים ל-RecyclerView
. אחרי שתסיימו את ה-codelab הזה, האפליקציה שלכם תיראה בדיוק אותו דבר, אבל היא תהיה יעילה יותר ויהיה קל יותר להרחיב ולתחזק אותה.
אתם יכולים להמשיך להשתמש באפליקציית SleepTracker מה-codelab הקודם, או להוריד את אפליקציית 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
יש API עשיר לעדכון של רכיב יחיד. אפשר להשתמש בפונקציה 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()
, ואז לוחצים על OK.
כך נוצרים stub בתוך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
, כולל שיטת ה-setter. אין יותר צורך בזה, כי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()
, ב-observer ב-sleepTrackerViewModel
, מחפשים את השגיאה שבה יש הפניה למשתנהdata
שמחקתם. - מחליפים את
adapter.data = it
בשיחה אלadapter.submitList(it)
. הקוד המעודכן מוצג בהמשך.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- מריצים את האפליקציה. היא תפעל מהר יותר, אבל יכול להיות שלא תשימו לב לשינוי אם הרשימה קצרה.
במשימה הזו, משתמשים באותה טכניקה כמו ב-codelabs הקודמים כדי להגדיר קשירת נתונים, ומבטלים את הקריאות ל-findViewById()
.
שלב 1: מוסיפים קשירת נתונים לקובץ הפריסה
- פותחים את קובץ הפריסה
list_item_sleep_night.xml
בכרטיסייה Text. - מציבים את הסמן על התג
ConstraintLayout
ומקישים עלAlt+Enter
(Option+Enter
ב-Mac). תפריט הכוונות (תפריט התיקון המהיר) ייפתח. - בוחרים באפשרות Convert to data binding layout (המרה לפריסת קשירת נתונים). הפעולה הזו עוטפת את הפריסה בתג
<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
, בוחרים באפשרות Build > Clean Project (בנייה > ניקוי הפרויקט), ואז בוחרים באפשרות Build > Rebuild Project (בנייה > בנייה מחדש של הפרויקט). (אם הבעיות נמשכות, בוחרים באפשרות קובץ > ביטול תוקף של מטמונים / הפעלה מחדש). אובייקט הקישור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) כדי לפתוח את תפריט הכוונות.
- בוחרים באפשרות Change parameter 'itemView' type of primary constructor of class 'ViewHolder' to 'ListItemSleepNightBinding' (שינוי סוג הפרמטר itemView של בנאי ראשי של המחלקה ViewHolder ל-ListItemSleepNightBinding). הפעולה הזו מעדכנת את סוג הפרמטר של המחלקה
ViewHolder
.
- גוללים למעלה להגדרת המחלקה של
ViewHolder
כדי לראות את השינוי בחתימה. מוצגת שגיאה לגביitemView
, כי שיניתם אתitemView
ל-binding
בשיטהfrom()
.
בהגדרת המחלקהViewHolder
, לוחצים לחיצה ימנית על אחד המקרים שלitemView
ובוחרים באפשרות Refactor (ארגון מחדש) > Rename (שינוי שם). משנים את השם ל-binding
. - מוסיפים את הקידומת
val
לפרמטר של ה-constructorbinding
כדי להפוך אותו למאפיין (property). - בשיחה למחלקת האב,
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
. בוחרים באפשרות Refactor > Inline (שינוי מבנה > הטמעה), או מקישים עלControl+Command+N
(Option+Command+N
ב-Mac). - מריצים את האפליקציה. (יכול להיות שתצטרכו לנקות ולבנות מחדש את הפרויקט אם יש בו שגיאות).
במשימה הזו תשדרגו את האפליקציה כדי להשתמש בקשירת נתונים עם מתאמי קשירה להגדרת הנתונים בתצוגות.
ב-codelab הקודם השתמשתם במחלקה Transformations
כדי לקחת את LiveData
וליצור מחרוזות מעוצבות להצגה בתצוגות טקסט. עם זאת, אם אתם צריכים לקשור סוגים שונים או סוגים מורכבים, אתם יכולים לספק מתאמי קשירה כדי לעזור לקשירת הנתונים להשתמש בסוגים האלה. מתאמי איגוד הם מתאמים שלוקחים את הנתונים שלכם ומעבדים אותם כך שניתן יהיה להשתמש בהם באיגוד נתונים כדי לאגד תצוגה, כמו טקסט או תמונה.
תטמיעו שלושה מתאמי קישור, אחד לתמונת האיכות ואחד לכל שדה טקסט. לסיכום, כדי להצהיר על מתאם binding, מגדירים שיטה שמקבלת פריט ותצוגה, ומוסיפים לה את ההערה @BindingAdapter
. בגוף השיטה, מטמיעים את הטרנספורמציה. ב-Kotlin, אפשר לכתוב מתאם של Binding כפונקציית הרחבה במחלקת התצוגה שמקבלת את הנתונים.
שלב 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()
. הקריאה הזו היא אופטימיזציה שמבקשת מ-data binding להפעיל מיד את כל הקישורים שממתינים להפעלה. תמיד מומלץ להתקשר אל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 Studio: RecyclerViewDiffUtilDataBinding.
DiffUtil
:
-
RecyclerView
כולל מחלקה בשםDiffUtil
שמשמשת לחישוב ההבדלים בין שתי רשימות. - ל-
DiffUtil
יש מחלקה בשםItemCallBack
שמרחיבים אותה כדי לגלות את ההבדל בין שתי רשימות. - במחלקת
ItemCallback
, צריך לבטל את השיטותareItemsTheSame()
ו-areContentsTheSame()
.
ListAdapter
:
- כדי לנהל רשימות בחינם, אפשר להשתמש במחלקה
ListAdapter
במקום במחלקהRecyclerView.Adapter
. עם זאת, אם משתמשים ב-ListAdapter
, צריך לכתוב מתאם משלכם עבור פריסות אחרות, ולכן במעבדת הקוד הזו מוסבר איך לעשות זאת. - כדי לפתוח את תפריט הכוונות ב-Android Studio, מציבים את הסמן על פריט קוד כלשהו ומקישים על
Alt+Enter
(או עלOption+Enter
ב-Mac). התפריט הזה שימושי במיוחד כשמבצעים רפקטורינג של קוד ויוצרים stubs להטמעת שיטות. התפריט תלוי הקשר, לכן צריך למקם את הסמן בדיוק במקום הנכון כדי לקבל את התפריט הנכון.
קישור נתונים:
- משתמשים בקשירת נתונים בפריסת הפריט כדי לקשור נתונים לתצוגות.
מתאמי כריכה:
- בעבר השתמשת ב-
Transformations
כדי ליצור מחרוזות מנתונים. אם אתם צריכים לקשור נתונים מסוגים שונים או מורכבים, אתם יכולים לספק מתאמי קשירה שיעזרו לקשירת הנתונים להשתמש בהם. - כדי להצהיר על מתאם קישור, מגדירים שיטה שמקבלת פריט ותצוגה, ומוסיפים לשיטה את ההערה
@BindingAdapter
. ב-Kotlin, אפשר לכתוב את מתאם הקישור כפונקציית הרחבה ב-View
. מעבירים את שם הנכס שהמתאם מתאים. לדוגמה:
@BindingAdapter("sleepDurationFormatted")
- בפריסת ה-XML, מגדירים מאפיין
app
עם אותו שם כמו של מתאם הקישור. מעבירים משתנה עם הנתונים. לדוגמה:
.app:sleepDurationFormatted="@{sleep}"
קורסים ב-Udacity:
מסמכי תיעוד למפתחי Android:
- יצירת רשימה באמצעות RecyclerView
RecyclerView
DiffUtil
- ספריית Data Binding
- מתאמי Binding
notifyDataSetChanged()
Transformations
מקורות מידע נוספים:
בקטע הזה מפורטות אפשרויות למשימות ביתיות לתלמידים שעובדים על ה-Codelab הזה כחלק מקורס בהנחיית מדריך. המורה צריך:
- אם צריך, מקצים שיעורי בית.
- להסביר לתלמידים איך להגיש מטלות.
- בודקים את שיעורי הבית.
אנשי ההוראה יכולים להשתמש בהצעות האלה כמה שרוצים, ומומלץ להם להקצות כל שיעורי בית אחרים שהם חושבים שמתאימים.
אם אתם עובדים על ה-codelab הזה לבד, אתם יכולים להשתמש במשימות האלה כדי לבדוק את הידע שלכם.
עונים על השאלות הבאות
שאלה 1
אילו מהפעולות הבאות נדרשות כדי להשתמש ב-DiffUtil
? יש לבחור בכל האפשרויות הרלוונטיות.
▢ הארכת השיעור ItemCallBack
.
▢ שינוי מברירת המחדל areItemsTheSame()
.
▢ שינוי מברירת המחדל areContentsTheSame()
.
▢ שימוש בקשירת נתונים כדי לעקוב אחרי ההבדלים בין פריטים.
שאלה 2
אילו מההצהרות הבאות נכונות לגבי מתאמי Binding?
▢ מתאם של קישור הוא פונקציה עם ההערה @BindingAdapter
.
▢ שימוש במתאם איגוד מאפשר להפריד בין עיצוב הנתונים לבין מחזיק התצוגה.
▢ אם רוצים להשתמש במתאמי איגוד, צריך להשתמש ב-RecyclerViewAdapter
.
▢ Binding adapters הם פתרון טוב כשצריך לשנות נתונים מורכבים.
שאלה 3
מתי כדאי להשתמש ב-Transformations
במקום במתאם איגוד? יש לבחור בכל האפשרויות הרלוונטיות.
▢ הנתונים שלכם פשוטים.
▢ אתם מעצבים מחרוזת.
▢ הרשימה ארוכה מאוד.
▢ ViewHolder
מכיל רק צפייה אחת.
להתחלת השיעור הבא: