‫Android Kotlin Fundamentals 06.3: Use LiveData to control button states

ה-codelab הזה הוא חלק מהקורס Android Kotlin Fundamentals. כדי להפיק את המרב מהקורס הזה, מומלץ לעבוד על ה-codelabs לפי הסדר. כל ה-codelab של הקורס מפורטים בדף הנחיתה של ה-codelab בנושא יסודות Kotlin ל-Android.

מבוא

בשיעור הזה נסביר איך להשתמש ב-ViewModel ובקטעים ביחד כדי להטמיע ניווט. חשוב לזכור שהמטרה היא להעביר את הלוגיקה של מתי לנווט אל ViewModel, אבל להגדיר את הנתיבים בקטעים ובקובץ הניווט. כדי להשיג את המטרה הזו, משתמשים במודלים של תצוגות, בקטעי קוד, ב-LiveData ובאובייקטים מסוג Observer.

בסיום ה-codelab מוצגת דרך חכמה לעקוב אחרי מצבי הלחצנים עם מינימום קוד, כך שכל לחצן מופעל וניתן ללחיצה רק כשיש היגיון בכך שהמשתמש יקיש על הלחצן הזה.

מה שכדאי לדעת

חשוב שתכירו את:

  • בניית ממשק משתמש (UI) בסיסי באמצעות פעילות, רכיבים ותצוגות.
  • ניווט בין פרגמנטים ושימוש ב-safeArgs כדי להעביר נתונים בין פרגמנטים.
  • אפשר לראות את המודלים, את מפעלי המודלים, את הטרנספורמציות ואת LiveData ואת האובזרברים שלהם.
  • איך יוצרים מסד נתונים Room, יוצרים אובייקט גישה לנתונים (DAO) ומגדירים ישויות.
  • איך משתמשים ב-coroutines לאינטראקציות עם מסדי נתונים ולמשימות אחרות שפועלות לאורך זמן.

מה תלמדו

  • איך מעדכנים רשומה קיימת של איכות השינה במסד הנתונים.
  • איך משתמשים ב-LiveData כדי לעקוב אחרי מצבי לחצנים.
  • איך להציג סנקבר בתגובה לאירוע.

הפעולות שתבצעו:

  • הרחבת האפליקציה TrackMySleepQuality כדי לאסוף דירוג איכות, להוסיף את הדירוג למסד הנתונים ולהציג את התוצאה.
  • משתמשים ב-LiveData כדי להפעיל את התצוגה של חטיף.
  • משתמשים ב-LiveData כדי להפעיל ולהשבית את הלחצנים.

בשיעור הזה תבנו את ההקלטה של איכות השינה ואת ממשק המשתמש הסופי של האפליקציה TrackMySleepQuality.

לאפליקציה יש שני מסכים שמיוצגים על ידי קטעים, כמו שמוצג באיור שלמטה.

במסך הראשון, שמוצג בצד ימין, יש לחצנים להתחלת המעקב ולהפסקתו. במסך מוצגים כל נתוני השינה של המשתמש. הלחצן ניקוי מוחק באופן סופי את כל הנתונים שהאפליקציה אספה על המשתמש.

במסך השני, שמוצג בצד שמאל, בוחרים את דירוג איכות השינה. באפליקציה, הדירוג מיוצג בצורה מספרית. למטרות פיתוח, האפליקציה מציגה גם את סמלי הפנים וגם את הערכים המספריים שלהם.

מסלול המשתמש הוא כדלקמן:

  • המשתמש פותח את האפליקציה ומוצג לו מסך מעקב השינה.
  • המשתמש מקיש על הלחצן התחלה. השדה הזה מתעד את שעת ההתחלה ומציג אותה. הלחצן התחלה מושבת, והלחצן עצירה מופעל.
  • המשתמש מקיש על הלחצן הפסקה. השעה שבה תסיימו לישון תתועד ותיפתח לכם האפשרות לדרג את איכות השינה.
  • המשתמש בוחר בסמל של איכות השינה. המסך נסגר, ובמסך המעקב מוצגים שעת סיום השינה ואיכות השינה. הלחצן עצירה מושבת והלחצן התחלה מופעל. האפליקציה מוכנה לעוד לילה.
  • הלחצן ניקוי מופעל בכל פעם שיש נתונים במסד הנתונים. כשמשתמש מקיש על הלחצן ניקוי, כל הנתונים שלו נמחקים בלי אפשרות לשחזור – לא מוצגת הודעה עם השאלה 'האם אתה בטוח?'.

האפליקציה הזו משתמשת בארכיטקטורה פשוטה, כפי שמוצג בהמשך בהקשר של הארכיטקטורה המלאה. האפליקציה משתמשת רק ברכיבים הבאים:

  • בקר ממשק משתמש
  • הצגת הדגם ו-LiveData
  • מסד נתונים של Room

בשיעור הזה אנחנו מניחים שאתם יודעים איך להטמיע ניווט באמצעות קטעים ואת קובץ הניווט. כדי שתוכלו לשמור את העבודה שלכם, סיפקנו חלק גדול מהקוד הזה.

שלב 1: בדיקת הקוד

  1. כדי להתחיל, אפשר להמשיך עם הקוד שלכם מסוף ה-codelab הקודם, או להוריד את הקוד לתחילת הדרך.
  2. בקוד המתחיל, בודקים את SleepQualityFragment. המחלקות האלה מרחיבות את הפריסה, מקבלות את האפליקציה ומחזירות את binding.root.
  3. פותחים את navigation.xml בכלי לעריכת עיצוב. אפשר לראות שיש נתיב ניווט מSleepTrackerFragment אל SleepQualityFragment, וחזרה מSleepQualityFragment אל SleepTrackerFragment.



  4. בודקים את הקוד של navigation.xml. בפרט, מחפשים את <argument> שנקרא sleepNightKey.

    כשהמשתמש עובר מ-SleepTrackerFragment ל-SleepQualityFragment,, האפליקציה תעביר sleepNightKey ל-SleepQualityFragment ללילה שצריך לעדכן.

שלב 2: הוספת ניווט למעקב אחר איכות השינה

תרשים הניווט כבר כולל את הנתיבים מSleepTrackerFragment אל SleepQualityFragment ובחזרה. עם זאת, עדיין לא נכתב קוד ל-click handlers שמטמיעים את הניווט מקטע אחד לקטע הבא. מוסיפים את הקוד הזה עכשיו ב-ViewModel.

ב-click handler, מגדירים LiveData שמשתנה כשרוצים שהאפליקציה תנווט ליעד אחר. הקטע מתייחס לLiveData. כשהנתונים משתנים, הפראגמנט עובר ליעד ומעדכן את מודל התצוגה שהוא סיים, מה שגורם לאיפוס של משתנה המצב.

  1. פתיחת SleepTrackerViewModel. צריך להוסיף ניווט כך שכשהמשתמש יקיש על הלחצן Stop, האפליקציה תנווט אל SleepQualityFragment כדי לאסוף דירוג איכות.
  2. ב-SleepTrackerViewModel, יוצרים LiveData שמשתנה כשרוצים שהאפליקציה תעבור אל SleepQualityFragment. משתמשים בהסתרת מידע כדי לחשוף רק גרסה שאפשר לקבל של LiveData אל ViewModel.

    אפשר להציב את הקוד הזה בכל מקום ברמה העליונה של גוף המחלקה.
private val _navigateToSleepQuality = MutableLiveData<SleepNight>()

val navigateToSleepQuality: LiveData<SleepNight>
   get() = _navigateToSleepQuality
  1. מוסיפים פונקציה doneNavigating() שמאפסת את המשתנה שמפעיל את הניווט.
fun doneNavigating() {
   _navigateToSleepQuality.value = null
}
  1. ב-click handler של הלחצן Stop‏, onStopTracking(), מפעילים את הניווט אל SleepQualityFragment. מגדירים את המשתנה _navigateToSleepQuality בסוף הפונקציה כדבר האחרון בתוך הבלוק launch{}. הערה: המשתנה הזה מוגדר לערך night. כשהמשתנה הזה מקבל ערך, האפליקציה עוברת אל SleepQualityFragment, ומעבירה את הלילה.
_navigateToSleepQuality.value = oldNight
  1. ה-SleepTrackerFragment צריך לעקוב אחרי _navigateToSleepQuality כדי שהאפליקציה תדע מתי לנווט. ב-SleepTrackerFragment, ב-onCreateView(), מוסיפים משקיף ל-navigateToSleepQuality(). שימו לב: הייבוא של זה לא חד-משמעי, ואתם צריכים לייבא את androidx.lifecycle.Observer.
sleepTrackerViewModel.navigateToSleepQuality.observe(this, Observer {
})

  1. בתוך בלוק הצופה, עוברים ומעבירים את המזהה של הלילה הנוכחי, ואז קוראים ל-doneNavigating(). אם הייבוא לא ברור, מייבאים את androidx.navigation.fragment.findNavController.
night ->
night?.let {
   this.findNavController().navigate(
           SleepTrackerFragmentDirections
                   .actionSleepTrackerFragmentToSleepQualityFragment(night.nightId))
   sleepTrackerViewModel.doneNavigating()
}
  1. מפתחים ומריצים את האפליקציה. מקישים על התחלה ואז על עצירה, ועוברים למסך SleepQualityFragment. כדי לחזור, משתמשים בלחצן 'הקודם' של המערכת.

במשימה הזו, מקליטים את איכות השינה וחוזרים אל קטע השינה. הערך המעודכן אמור להופיע למשתמש באופן אוטומטי. צריך ליצור ViewModel וViewModelFactory, ולעדכן את SleepQualityFragment.

שלב 1: יצירת ViewModel ו-ViewModelFactory

  1. בחבילה sleepquality, יוצרים או פותחים את SleepQualityViewModel.kt.
  2. יוצרים מחלקה SleepQualityViewModel שמקבלת sleepNightKey ומסד נתונים כארגומנטים. בדיוק כמו שעשיתם בשלב SleepTrackerViewModel, אתם צריכים להעביר את database מהמפעל. צריך גם להעביר את sleepNightKey מהניווט.
class SleepQualityViewModel(
       private val sleepNightKey: Long = 0L,
       val database: SleepDatabaseDao) : ViewModel() {
}
  1. בתוך המחלקה SleepQualityViewModel, מגדירים את Job ואת uiScope, ומבטלים את ההגדרה של onCleared().
private val viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}
  1. כדי לחזור אל SleepTrackerFragment באמצעות אותו דפוס כמו למעלה, מצהירים על _navigateToSleepTracker. מטמיעים את navigateToSleepTracker ואת doneNavigating().
private val _navigateToSleepTracker = MutableLiveData<Boolean?>()

val navigateToSleepTracker: LiveData<Boolean?>
   get() = _navigateToSleepTracker

fun doneNavigating() {
   _navigateToSleepTracker.value = null
}
  1. יוצרים handler של קליק אחד, onSetSleepQuality(), לכל התמונות של איכות השינה.

    משתמשים באותו דפוס של קורוטינה כמו ב-codelab הקודם:
  • מפעילים קורוטינה ב-uiScope ועוברים למפיץ של קלט/פלט.
  • קבלת tonight באמצעות sleepNightKey.
  • מגדירים את איכות השינה.
  • מעדכנים את מסד הנתונים.
  • הפעלת ניווט.

שימו לב שדוגמת הקוד שבהמשך מבצעת את כל העבודה ב-click handler, במקום להוציא את פעולת מסד הנתונים בהקשר שונה.

fun onSetSleepQuality(quality: Int) {
        uiScope.launch {
            // IO is a thread pool for running operations that access the disk, such as
            // our Room database.
            withContext(Dispatchers.IO) {
                val tonight = database.get(sleepNightKey) ?: return@withContext
                tonight.sleepQuality = quality
                database.update(tonight)
            }

            // Setting this state variable to true will alert the observer and trigger navigation.
            _navigateToSleepTracker.value = true
        }
    }
  1. בחבילה sleepquality, יוצרים או פותחים את SleepQualityViewModelFactory.kt ומוסיפים את המחלקה SleepQualityViewModelFactory, כמו שמוצג בהמשך. בשיעור הזה נעשה שימוש בגרסה של אותו קוד boilerplate שראיתם קודם. כדאי לבדוק את הקוד לפני שממשיכים.
class SleepQualityViewModelFactory(
       private val sleepNightKey: Long,
       private val dataSource: SleepDatabaseDao) : ViewModelProvider.Factory {
   @Suppress("unchecked_cast")
   override fun <T : ViewModel?> create(modelClass: Class<T>): T {
       if (modelClass.isAssignableFrom(SleepQualityViewModel::class.java)) {
           return SleepQualityViewModel(sleepNightKey, dataSource) as T
       }
       throw IllegalArgumentException("Unknown ViewModel class")
   }
}

שלב 2: מעדכנים את SleepQualityFragment

  1. פתיחת SleepQualityFragment.kt.
  2. ב-onCreateView(), אחרי שמקבלים את application, צריך לקבל את arguments שמגיעה עם הניווט. הארגומנטים האלה מופיעים ב-SleepQualityFragmentArgs. צריך לחלץ אותם מהחבילה.
val arguments = SleepQualityFragmentArgs.fromBundle(arguments!!)
  1. בשלב הבא, מקבלים את dataSource.
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
  1. יוצרים מפעל ומעבירים את dataSource ואת sleepNightKey.
val viewModelFactory = SleepQualityViewModelFactory(arguments.sleepNightKey, dataSource)
  1. קבלת הפניה למסמך או קישור בסך ViewModel.
val sleepQualityViewModel =
       ViewModelProviders.of(
               this, viewModelFactory).get(SleepQualityViewModel::class.java)
  1. מוסיפים את ViewModel לאובייקט הקישור. (אם מופיעה שגיאה באובייקט של הקישור, אפשר להתעלם ממנה בשלב הזה).
binding.sleepQualityViewModel = sleepQualityViewModel
  1. מוסיפים את הצופה. כשמופיעה בקשה, מייבאים את androidx.lifecycle.Observer.
sleepQualityViewModel.navigateToSleepTracker.observe(this, Observer {
   if (it == true) { // Observed state is true.
       this.findNavController().navigate(
               SleepQualityFragmentDirections.actionSleepQualityFragmentToSleepTrackerFragment())
       sleepQualityViewModel.doneNavigating()
   }
})

שלב 3: מעדכנים את קובץ הפריסה ומריצים את האפליקציה

  1. פותחים את קובץ הפריסה fragment_sleep_quality.xml. בבלוק <data>, מוסיפים משתנה ל-SleepQualityViewModel.
 <data>
       <variable
           name="sleepQualityViewModel"
           type="com.example.android.trackmysleepquality.sleepquality.SleepQualityViewModel" />
   </data>
  1. לכל אחת משש התמונות של איכות השינה, מוסיפים click handler כמו זה שמופיע למטה. התאימו את דירוג האיכות לתמונה.
android:onClick="@{() -> sleepQualityViewModel.onSetSleepQuality(5)}"
  1. מנקים את הפרויקט ובונים אותו מחדש. הפעולה הזו אמורה לפתור את כל השגיאות באובייקט הקישור. אחרת, מנקים את המטמון (File > Invalidate Caches / Restart) ובונים מחדש את האפליקציה.

מעולה! הרגע יצרתם אפליקציית מסד נתונים מלאה של Room באמצעות קורוטינות.

עכשיו האפליקציה פועלת בצורה מצוינת. המשתמש יכול להקיש על התחלה ועל עצירה כמה פעמים שרוצה. כשהמשתמש מקיש על הפסקה, הוא יכול להזין את איכות השינה. כשהמשתמש מקיש על ניקוי, כל הנתונים מנוקים בשקט ברקע. עם זאת, כל הלחצנים תמיד מופעלים ואפשר ללחוץ עליהם, מה שלא גורם לאפליקציה לקרוס, אבל מאפשר למשתמשים ליצור לילות שינה לא מלאים.

במשימה האחרונה נלמד איך להשתמש במיפוי טרנספורמציות כדי לנהל את הנראות של הלחצנים, כך שהמשתמשים יוכלו לבחור רק את האפשרות הנכונה. אפשר להשתמש בשיטה דומה כדי להציג הודעה ידידותית אחרי שכל הנתונים נמחקו.

שלב 1: עדכון מצבי הכפתורים

הרעיון הוא להגדיר את מצב הלחצן כך שבהתחלה רק הלחצן התחלה יהיה מופעל, כלומר ניתן ללחוץ עליו.

אחרי שהמשתמש מקיש על התחלה, הכפתור עצירה מופעל והכפתור התחלה מושבת. הלחצן ניקוי מופעל רק אם יש נתונים במסד הנתונים.

  1. פותחים את קובץ הפריסה fragment_sleep_tracker.xml.
  2. מוסיפים את המאפיין android:enabled לכל לחצן. המאפיין android:enabled הוא ערך בוליאני שמציין אם הלחצן מופעל או לא. (אפשר להקיש על לחצן מופעל, אבל אי אפשר להקיש על לחצן מושבת). נותנים למאפיין את הערך של משתנה מצב שנגדיר עוד מעט.

start_button:

android:enabled="@{sleepTrackerViewModel.startButtonVisible}"

stop_button:

android:enabled="@{sleepTrackerViewModel.stopButtonVisible}"

clear_button:

android:enabled="@{sleepTrackerViewModel.clearButtonVisible}"
  1. פותחים את SleepTrackerViewModel ויוצרים שלושה משתנים תואמים. מקצים לכל משתנה טרנספורמציה שבודקת אותו.
  • הלחצן התחלה צריך להיות זמין כשערך המשתנה tonight הוא null.
  • הלחצן Stop (עצירה) צריך להיות זמין כשהערך של tonight הוא לא null.
  • הלחצן ניקוי צריך להיות זמין רק אם nights, ומכאן גם מסד הנתונים, מכיל נתוני שינה.
val startButtonVisible = Transformations.map(tonight) {
   it == null
}
val stopButtonVisible = Transformations.map(tonight) {
   it != null
}
val clearButtonVisible = Transformations.map(nights) {
   it?.isNotEmpty()
}
  1. מריצים את האפליקציה ומתנסים בלחצנים.

שלב 2: שימוש בחטיף כדי להודיע למשתמש

אחרי שהמשתמש מוחק את מסד הנתונים, מציגים לו אישור באמצעות הווידג'ט Snackbar. סרגל אינטראקטיבי מספק משוב קצר על פעולה באמצעות הודעה בתחתית המסך. סרגל החטיפים נעלם אחרי פרק זמן קצוב לתפוגה, אחרי אינטראקציה של המשתמש במקום אחר במסך או אחרי שהמשתמש מחליק את סרגל החטיפים אל מחוץ למסך.

הצגת הסנאקבר היא משימה שקשורה לממשק המשתמש, והיא צריכה להתבצע ב-fragment. ההחלטה להציג את חטיף המידע מתקבלת ב-ViewModel. כדי להגדיר ולהפעיל סנאקבר כשהנתונים נמחקים, אפשר להשתמש באותה טכניקה שמשמשת להפעלת ניווט.

  1. ב-SleepTrackerViewModel, יוצרים את האירוע המקופסל.
private var _showSnackbarEvent = MutableLiveData<Boolean>()

val showSnackBarEvent: LiveData<Boolean>
   get() = _showSnackbarEvent
  1. לאחר מכן מטמיעים את doneShowingSnackbar().
fun doneShowingSnackbar() {
   _showSnackbarEvent.value = false
}
  1. ב-SleepTrackerFragment, ב-onCreateView(), מוסיפים משקיף:
sleepTrackerViewModel.showSnackBarEvent.observe(this, Observer { })
  1. בתוך בלוק ה-observer, מציגים את ה-snackbar ומאפסים את האירוע באופן מיידי.
   if (it == true) { // Observed state is true.
       Snackbar.make(
               activity!!.findViewById(android.R.id.content),
               getString(R.string.cleared_message),
               Snackbar.LENGTH_SHORT // How long to display the message.
       ).show()
       sleepTrackerViewModel.doneShowingSnackbar()
   }
  1. ב-SleepTrackerViewModel, מפעילים את האירוע בשיטה onClear(). כדי לעשות זאת, מגדירים את ערך האירוע ל-true בתוך הבלוק launch:
_showSnackbarEvent.value = true
  1. יוצרים ומריצים את האפליקציה.

פרויקט Android Studio: ‏ TrackMySleepQualityFinal

הטמעת מעקב אחר איכות השינה באפליקציה הזו היא כמו השמעה של יצירה מוזיקלית מוכרת בסולם חדש. הפרטים משתנים, אבל הדפוס הבסיסי של מה שעשיתם ב-codelab הקודם בשיעור הזה נשאר זהה. ההיכרות עם הדפוסים האלה מאפשרת לתכנת הרבה יותר מהר, כי אפשר לעשות שימוש חוזר בקוד מאפליקציות קיימות. אלה חלק מהדפוסים שבהם השתמשנו בקורס הזה עד עכשיו:

  • יוצרים ViewModel וViewModelFactory ומגדירים מקור נתונים.
  • הפעלת ניווט. כדי להפריד בין הבעיות, כדאי להציב את click handler במודל התצוגה ואת הניווט בקטע.
  • משתמשים באנקפסולציה עם LiveData כדי לעקוב אחרי שינויים במצב ולהגיב להם.
  • שימוש בטרנספורמציות עם LiveData.
  • יצירת מסד נתונים יחיד.
  • הגדרת קורוטינות לפעולות במסד נתונים.

הפעלת ניווט

אתם מגדירים קובץ ניווט עם נתיבי ניווט אפשריים בין פרגמנטים. יש כמה דרכים להפעיל ניווט מקטע אחד לקטע הבא. למשל:

  • הגדרת רכיבי handler של onClick להפעלת ניווט אל קטע יעד.
  • לחלופין, כדי להפעיל את הניווט מקטע אחד לקטע הבא:
  • מגדירים ערך של LiveData כדי לתעד אם הניווט צריך להתבצע.
  • מצרפים אובייקט Observer לערך LiveData.
  • לאחר מכן, הקוד משנה את הערך הזה בכל פעם שצריך להפעיל ניווט או כשהניווט מסתיים.

הגדרת המאפיין android:enabled

  • המאפיין android:enabled מוגדר ב-TextView ומועבר בירושה לכל מחלקות המשנה, כולל Button.
  • המאפיין android:enabled קובע אם View מופעל או לא. המשמעות של 'מופעל' משתנה בהתאם למחלקת המשנה. לדוגמה, אם התכונה EditText לא מופעלת, המשתמש לא יכול לערוך את הטקסט שמופיע בתוכה, ואם התכונה Button לא מופעלת, המשתמש לא יכול להקיש על הלחצן.
  • המאפיין enabled שונה מהמאפיין visibility.
  • אפשר להשתמש במיפוי טרנספורמציות כדי להגדיר את הערך של מאפיין enabled של לחצנים על סמך המצב של אובייקט או משתנה אחר.

נקודות נוספות שמוסברות ב-Codelab הזה:

  • כדי להפעיל התראות למשתמש, אפשר להשתמש באותה טכניקה שבה משתמשים כדי להפעיל ניווט.
  • אפשר להשתמש בSnackbar כדי להודיע למשתמש.

קורס ב-Udacity:

מסמכי תיעוד למפתחי Android:

בקטע הזה מפורטות אפשרויות למשימות ביתיות לתלמידים שעובדים על ה-Codelab הזה כחלק מקורס בהנחיית מדריך. המורה צריך:

  • אם צריך, מקצים שיעורי בית.
  • להסביר לתלמידים איך להגיש מטלות.
  • בודקים את שיעורי הבית.

אנשי ההוראה יכולים להשתמש בהצעות האלה כמה שרוצים, ומומלץ להם להקצות כל שיעורי בית אחרים שהם חושבים שמתאימים.

אם אתם עובדים על ה-codelab הזה לבד, אתם יכולים להשתמש במשימות האלה כדי לבדוק את הידע שלכם.

עונים על השאלות הבאות

שאלה 1

אחת הדרכים לאפשר לאפליקציה להפעיל ניווט מקטע אחד לקטע הבא היא להשתמש בערך LiveData כדי לציין אם להפעיל ניווט או לא.

מה השלבים לשימוש בערך LiveData, שנקרא gotoBlueFragment, כדי להפעיל ניווט מהקטע האדום לקטע הכחול? עליך לבחור בכל האפשרויות המתאימות:

  • בקטע ViewModel, מגדירים את הערך LiveData gotoBlueFragment.
  • ב-RedFragment, בודקים את הערך gotoBlueFragment. מטמיעים את הקוד observe{} כדי לנווט אל BlueFragment כשצריך, ואז מאפסים את הערך של gotoBlueFragment כדי לציין שהניווט הושלם.
  • מוודאים שהמשתנה gotoBlueFragment מוגדר בקוד לערך שמפעיל את הניווט בכל פעם שהאפליקציה צריכה לעבור מ-RedFragment ל-BlueFragment.
  • מוודאים שהקוד מגדיר handler של onClick עבור View שהמשתמש לוחץ עליו כדי לנווט אל BlueFragment, וש-handler של onClick מתבונן בערך goToBlueFragment.

שאלה 2

אתם יכולים לשנות את ההגדרה של Button כך שהיא תהיה מופעלת (ניתן ללחוץ עליה) או לא באמצעות LiveData. איך אפשר לוודא שהאפליקציה משנה את הכפתור UpdateNumber כך ש:

  • הלחצן מופעל אם הערך של myNumber גדול מ-5.
  • הלחצן לא מופעל אם הערך של myNumber הוא 5 או פחות.

נניח שהפריסה שמכילה את הלחצן UpdateNumber כוללת את המשתנה <data> עבור NumbersViewModel כמו שמוצג כאן:

<data>
   <variable
       name="NumbersViewModel"
       type="com.example.android.numbersapp.NumbersViewModel" />
</data>

נניח שהמזהה של הלחצן בקובץ הפריסה הוא:

android:id="@+id/update_number_button"

מה עוד צריך לעשות? יש לבחור בכל האפשרויות הרלוונטיות.

  • במחלקה NumbersViewModel, מגדירים משתנה LiveData, ‏ myNumber, שמייצג את המספר. בנוסף, מגדירים משתנה שהערך שלו נקבע על ידי קריאה לפונקציה Transform.map() על המשתנה myNumber, שמחזירה ערך בוליאני שמציין אם המספר גדול מ-5 או לא.

    באופן ספציפי, מוסיפים את הקוד הבא ל-ViewModel:
val myNumber: LiveData<Int>

val enableUpdateNumberButton = Transformations.map(myNumber) {
   myNumber > 5
}
  • בפריסת ה-XML, מגדירים את המאפיין android:enabled של update_number_button button לערך NumberViewModel.enableUpdateNumbersButton.
android:enabled="@{NumbersViewModel.enableUpdateNumberButton}"
  • ברכיב Fragment שמשתמש במחלקה NumbersViewModel, מוסיפים משקיף למאפיין enabled של הלחצן.

    באופן ספציפי, מוסיפים את הקוד הבא ל-Fragment:
// Observer for the enabled attribute
viewModel.enabled.observe(this, Observer<Boolean> { isEnabled ->
   myNumber > 5
})
  • בקובץ הפריסה, מגדירים את המאפיין android:enabled של update_number_button button ל-"Observable".

עוברים לשיעור הבא: 7.1 יסודות RecyclerView

קישורים ל-codelabs אחרים בקורס הזה מופיעים בדף הנחיתה של ה-codelabs בנושא יסודות Android Kotlin.