Lab Lab זה הוא חלק מקורס Android Kotlin Fundamentals. כדי להפיק את המקסימום מהקורס הזה, יש לפעול ברצף לפי קודי שיעור ה-Lab. כל שיעורי Lab של הקורסים מופיעים בדף הנחיתה של Lab Kotlin Fundamentals ל-Android Lab.
מבוא
במעבדות הקוד הקודמות של השיעור הזה למדת איך לקבל נתונים על נדל"ן ממצפה משירות אינטרנט, ואיך ליצור RecyclerView
עם פריסת רשת כדי לטעון ולהציג תמונות מהנתונים האלה. בשיעור ה-Lab הזה מסיימים את אפליקציית MarsRealEstate על ידי יישום היכולת לסנן את הנכסים ב-Mars לפי נכסים להשכרה או לרכישה. בנוסף, אתם יוצרים תצוגת פרטים כך שאם המשתמש מקיש על תמונת נכס בסקירה הכללית, הוא יראה תצוגת פרטים עם פרטים על הנכס הזה.
מה כבר צריך לדעת
- איך ליצור קטעי קוד ולהשתמש בהם.
- איך לנווט בין מקטעים ומשתמשים ב-safe Args (פלאגין של Gradle) כדי לעבור בין נתונים
- כיצד להשתמש ברכיבי ארכיטקטורה, כולל מודלים של תצוגה, מפעלי תצוגה, טרנספורמציות ו-
LiveData
. - איך לאחזר נתונים מקודדים מסוג JSON משירות אינטרנט של REST ולנתח את הנתונים האלה באובייקטים של Kotlin באמצעות הספריות Retrofit ו-Moshi.
מה תלמדו
- איך להשתמש בביטויים מחייבים מורכבים בקובצי הפריסה.
- איך לשלוח בקשות רטרופיט לשירות אינטרנט עם אפשרויות שאילתה.
מה צריך לעשות
- יש לשנות את אפליקציית MarsRealEstate כדי לסמן את הנכסים ב'מאדים' למכירה (לעומת נכסים להשכרה) באמצעות סמל סימן דולר.
- כדי לפתוח בקשה לשירות אינטרנט, שמסננת את נכסי המאדים לפי סוג, משתמשים בתפריט האפשרויות שבדף הסקירה הכללית.
- יוצרים מקטע מפורט עבור נכס מאדים, מחברים את הפלח הזה לתצוגת הסקירה הכללית באמצעות ניווט ומעבירים את נתוני הנכס לקטע הזה.
ב-Codelab הזה (ובקודי codelab קשורים) אתם עובדים עם אפליקציה שנקראת MarsRealEstate, שמציגה נכסים למכירה במאדים. האפליקציה הזו מתחברת לשרת אינטרנט כדי לאחזר ולהציג נתוני נכסים, כולל פרטים כמו המחיר והאם הנכס זמין למכירה או להשכרה. התמונות שמייצגות כל נכס הן תמונות מהחיים במאדים שצולמו על ידי רכבי הירח במאדים. ב-codelabs קודמים, יצרתם RecyclerView
עם פריסת רשת עבור כל התמונות של הנכסים:
בגרסה הזו של האפליקציה, אתם עובדים עם סוג הנכס (השכרה לעומת קנייה) ומוסיפים סמל לפריסת הרשת כדי לסמן נכסים למכירה:
אתם משנים את תפריט האפשרויות של האפליקציה כדי לסנן את תצוגת המשבצות כך שיוצגו בה רק הנכסים להשכרה או למכירה:
בנוסף, אתם יוצרים תצוגת פרטים של נכס ספציפי, ומחברים את הסמלים בתצוגת הסקירה הכללית לקטע הקוד של הניווט הזה:
עד עכשיו, החלק היחיד של נתוני הנכס ב-Mars שבו השתמשתם הוא כתובת ה-URL של תמונת הנכס. עם זאת, נתוני הנכס (שהגדרתם בכיתה MarsProperty
) כוללים גם מזהה, מחיר וסוג (השכרה או למכירה). כדי לרענן את הזיכרון, הנה קטע קוד של נתוני ה-JSON שקיבלת משירות האינטרנט:
{
"price":8000000,
"id":"424908",
"type":"rent",
"img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631290305226E03_DXXX.jpg"
},
במשימה הזו, מתחילים לעבוד עם סוג הנכס Mars כדי להוסיף תמונה של סימן דולר לנכסים בדף הסקירה הכללית למכירה.
שלב 1: מעדכנים את נכס המאדים כך שיכלול את הסוג
הסיווג MarsProperty
מגדיר את מבנה הנתונים של כל נכס שסופק על ידי שירות האינטרנט. במעבדת קוד קודמת, השתמשתם בספרייה Moshi כדי לנתח את תגובת ה-JSON הגולמית משירות האינטרנט של Mars לאובייקטים ספציפיים של נתונים מסוג MarsProperty
.
בשלב זה מוסיפים לוגיקה לכיתה MarsProperty
כדי לציין אם נכס מיועד להשכרה או לא (כלומר, אם הסוג הוא המחרוזת "rent"
או "buy"
). עליכם להשתמש בלוגיקה הזו ביותר ממקום אחד, ולכן עדיף שהיא תוצג כאן בקבוצת הנתונים במקום לשכפל אותה.
- פותחים את אפליקציית MarsRealEstate ממעבדת הקוד האחרונה. (אם אין לך את האפליקציה, אפשר להוריד את MarsRealEstateGrid).
- פתיחת
network/MarsProperty.kt
צריך להוסיף גוף להגדרת הכיתה שלMarsProperty
, ולהוסיף גיטר בהתאמה אישית עבורisRental
שמחזירtrue
אם האובייקט הוא מסוג"rent"
.
data class MarsProperty(
val id: String,
@Json(name = "img_src") val imgSrcUrl: String,
val type: String,
val price: Double) {
val isRental
get() = type == "rent"
}
שלב 2: מעדכנים את פריסת הפריט ברשת
עכשיו אתם מעדכנים את פריסת הפריטים ברשת התמונות כדי להציג שרטוט של סימן דולר רק בתמונות מהנכס שאתם מוכרים.
בעזרת ביטויים של קישור נתונים אפשר לבצע את הבדיקה הזו באופן מלא בפריסת ה-XML של פריטי הרשת.
- פתיחת
res/layout/grid_view_item.xml
זהו קובץ הפריסה של כל תא בפריסת רשת שלRecyclerView
. הקובץ מכיל כרגע רק את הרכיב<ImageView>
של תמונת הנכס. - בתוך האלמנט
<data>
, מוסיפים רכיב<import>
לכיתהView
. ייבוא משמש כשרוצים להשתמש ברכיבים של כיתה בביטוי לביטוי קישור נתונים בקובץ פריסה. במקרה כזה, צריך להשתמש בקבועיםView.GONE
ו-View.VISIBLE
, ולכן נדרשת גישה למחלקהView
.
<import type="android.view.View"/>
- צריך להקיף את כל תצוגת התמונה בסימן
FrameLayout
כדי לאפשר שרטוט של סימן הדולר מעל לתמונה של הנכס.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ImageView
android:id="@+id/mars_image"
...
</FrameLayout>
- עבור
ImageView
, יש לשנות את המאפייןandroid:layout_height
ל-match_parent
כדי למלא את הערכים של ההורה החדשFrameLayout
.
android:layout_height="match_parent"
- יש להוסיף רכיב
<ImageView>
שני מתחת לרכיב הראשון, בתוך ה-FrameLayout
. אפשר להשתמש בהגדרה שבהמשך. התמונה הזו מופיעה בפינה השמאלית התחתונה של הפריט ברשת, מעל לתמונה של מאדים, ומשתמשת בשרטוט שנקבע ב-res/drawable/ic_for_sale_outline.xml
כדי לסמן את סמל הדולר.
<ImageView
android:id="@+id/mars_property_type"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="bottom|end"
android:adjustViewBounds="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_for_sale_outline"
tools:src="@drawable/ic_for_sale_outline"/>
- יש להוסיף את המאפיין
android:visibility
לתצוגת התמונהmars_property_type
. משתמשים בביטוי מחייב כדי לבדוק את סוג הנכס, ומקצים את החשיפה ל-View.GONE
(להשכרה) או ל-View.VISIBLE
(לרכישה).
android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"
עד עכשיו ראית רק ביטויים מחייבים בפריסות שמשתמשות במשתנים נפרדים שהוגדרו ברכיב <data>
. ביטויי קישור הם עוצמתיים ביותר ומאפשרים לבצע פעולות כמו בדיקות וחישובים מתמטיים בלבד בתוך פריסת ה-XML. במקרה כזה, משתמשים באופרטור "טרינרי" (?:
) כדי לבצע בדיקה (האובייקט הזה הוא השכרה?). יש לספק תוצאה אחת כ-true (הסתרה של סמל הדולר עם View.GONE
) ותוצאה אחרת כ-false (הצגת הסמל הזה עם View.VISIBLE
).
הקובץ המלא החדש grid_view_item.xml
מוצג בהמשך:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View"/>
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ImageView
android:id="@+id/mars_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
android:padding="2dp"
app:imageUrl="@{property.imgSrcUrl}"
tools:src="@tools:sample/backgrounds/scenic"/>
<ImageView
android:id="@+id/mars_property_type"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="bottom|end"
android:adjustViewBounds="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_for_sale_outline"
android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"
tools:src="@drawable/ic_for_sale_outline"/>
</FrameLayout>
</layout>
- הידור והפעלה של האפליקציה, לתשומת ליבך: נכסים שאינם שכרים מופיעים עם סמל הדולר.
נכון לעכשיו, האפליקציה שלך מציגה את כל מאפייני המאדים ברשת הסקירה הכללית. אם משתמש מחפש נכס להשכרה במאדים, אפשר להשתמש בסמלים כדי לציין אילו מהנכסים הזמינים למכירה הם שימושיים, אבל עדיין יש הרבה נכסים שצריך לגלול בדף. במשימה הזו מוסיפים תפריט אפשרויות לקטע הסקירה הכללית, שמאפשר למשתמש להציג רק נכסים להשכרה, רק נכסים למכירה או להציג הכול.
דרך אחת לבצע את המשימה הזו היא לבדוק את הסוג של כל MarsProperty
ברשת הסקירה הכללית ולהציג רק את הנכסים התואמים. עם זאת, לשירות האינטרנט בפועל של Mars יש פרמטר או אפשרות שאילתה (שנקראים filter
) שמאפשר לקבל רק מאפיינים מסוג rent
או מסוג buy
. תוכל להשתמש בשאילתת הסינון הזו עם כתובת האתר של שירות האינטרנט realestate
בדפדפן הבא:
https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buy
במשימה הזו, צריך לשנות את המחלקה MarsApiService
כדי להוסיף אפשרות שאילתה לבקשה של שירות אינטרנט עם Retrofit. לאחר מכן, מתחברים מחדש לתפריט האפשרויות כדי להוריד מחדש את כל נתוני הנכסים ב-Mars באמצעות אפשרות השאילתה הזו. מאחר שהתגובה שאתם מקבלים משירות האינטרנט מכילה רק את הנכסים שמעניינים אתכם, אין צורך לשנות כלל את הלוגיקה של תצוגת התצוגה עבור רשת הסקירה הכללית.
שלב 1: עדכון שירות Mars API
כדי לשנות את הבקשה, עליך לחזור לקורס MarsApiService
שהוטמע ב-codelab הראשון בסדרה הזו. אתם משנים את הכיתה כדי לספק API לסינון.
- פתיחת
network/MarsApiService.kt
מתחת לייבוא, יוצריםenum
בשםMarsApiFilter
כדי להגדיר קבועות שתואמות לערכי השאילתה שאליהם שירות האינטרנט מצפה.
enum class MarsApiFilter(val value: String) {
SHOW_RENT("rent"),
SHOW_BUY("buy"),
SHOW_ALL("all") }
- יש לשנות את השיטה
getProperties()
כדי לקבל קלט מחרוזת עבור שאילתת המסנן, ולהוסיף הערות באמצעות@Query("filter")
, כפי שמוצג למטה.
יש לייבא אתretrofit2.http.Query
כשתופיע הבקשה.
ההערה ב-@Query
מורה לשיטהgetProperties()
(וכך מבצעת רטרופיט) להגיש את בקשת שירות האינטרנט עם אפשרות הסינון. בכל פעם שמתבצעת קריאה ל-getProperties()
, כתובת ה-URL של הבקשה כוללת את החלק?filter=type
, שמפנה את שירות האינטרנט להגיב לתוצאות שתואמות לשאילתה הזו.
fun getProperties(@Query("filter") type: String):
שלב 2: עדכון מודל תצוגת הסקירה הכללית
ביקשת נתונים מ-MarsApiService
בשיטת getMarsRealEstateProperties()
ב-OverviewViewModel
. עכשיו צריך לעדכן את הבקשה כך שתחול ארגומנט הסינון.
- פתיחת
overview/OverviewViewModel.kt
תבחינו בשגיאות ב-Android Studio עקב השינויים שביצעתם בשלב הקודם. צריך להוסיףMarsApiFilter
(המספר הכולל של ערכי המסננים האפשריים) כפרמטר לקריאה ל-getMarsRealEstateProperties()
.
ייבוא שלcom.example.android.marsrealestate.network.MarsApiFilter
לפי בקשה.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
- יש לשנות את הקריאה ל-
getProperties()
בשירות Retrofit כדי להעביר את שאילתת הסינון הזו כמחרוזת.
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)
- בבלוק
init {}
, יש להעביר אתMarsApiFilter.SHOW_ALL
כארגומנט אלgetMarsRealEstateProperties()
כדי להציג את כל הנכסים בפעם הראשונה שהאפליקציה נטענת.
init {
getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
- בסוף הכיתה, מוסיפים שיטה
updateFilter()
שמובילה לארגומנטMarsApiFilter
וקוראיםgetMarsRealEstateProperties()
לארגומנט הזה.
fun updateFilter(filter: MarsApiFilter) {
getMarsRealEstateProperties(filter)
}
שלב 3: מחברים את המקטע לתפריט האפשרויות
השלב האחרון הוא לחבר את תפריט האפשרויות הנוספות לקטע הקוד כדי להפעיל את updateFilter()
בדגם התצוגה המפורטת כשהמשתמש בוחר אפשרות בתפריט.
- פתיחת
res/menu/overflow_menu.xml
לאפליקציית MarsRealEstate יש תפריט אפשרויות נוספות, שכולל את שלוש האפשרויות הזמינות: הצגת כל הנכסים, הצגת נכסים להשכרה בלבד והצגה רק של נכסים למכירה.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/show_all_menu"
android:title="@string/show_all" />
<item
android:id="@+id/show_rent_menu"
android:title="@string/show_rent" />
<item
android:id="@+id/show_buy_menu"
android:title="@string/show_buy" />
</menu>
- פתיחת
overview/OverviewFragment.kt
בסוף הכיתה, צריך ליישם את השיטהonOptionsItemSelected()
כדי לבחור פריטים בתפריט.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
}
- ב-
onOptionsItemSelected()
, יש להתקשר לשיטהupdateFilter()
במודל התצוגה המפורטת עם המסנן המתאים. יש להשתמש בבלוקwhen {}
של Kotlin כדי לעבור בין האפשרויות. שימוש בערךMarsApiFilter.SHOW_ALL
כערך ברירת המחדל של המסנן. החזרתtrue
, כי טיפלת בפריט התפריט. מייבאים אתMarsApiFilter
(com.example.android.marsrealestate.network.MarsApiFilter
) כשמוצגת בקשה לעשות זאת. השיטה המלאה שלonOptionsItemSelected()
מוצגת בהמשך.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
viewModel.updateFilter(
when (item.itemId) {
R.id.show_rent_menu -> MarsApiFilter.SHOW_RENT
R.id.show_buy_menu -> MarsApiFilter.SHOW_BUY
else -> MarsApiFilter.SHOW_ALL
}
)
return true
}
- הידור והפעלה של האפליקציה. האפליקציה מפעילה את רשת הסקירה הכללית הראשונה עם כל סוגי הנכסים והנכסים למכירה המסומנים בסמל הדולר.
- בוחרים באפשרות השכרה בתפריט האפשרויות. המאפיינים נטענים מחדש ואף אחד מהם לא מופיע עם סמל הדולר. (מוצגים רק נכסים להשכרה). ייתכן שתצטרכו להמתין מספר דקות עד שהמסך יתרענן כדי להציג רק את הנכסים המסוננים.
- בוחרים באפשרות קנייה מתפריט האפשרויות. הנכסים נטענים מחדש וכולם מופיעים עם סמל הדולר. (מוצגים רק נכסים למכירה).
עכשיו מופיעה רשת גלילה של סמלים עבור נכסים של מאדים, אבל הגיע הזמן לקבל פרטים נוספים. במשימה הזו מוסיפים מקטעים של פרטים כדי להציג את הפרטים של נכס ספציפי. קטע המידע יציג תמונה גדולה יותר, מחיר וסוג הנכס — בין אם מדובר בהשכרה או למכירה.
קטע זה מופעל כשהמשתמש מקיש על תמונה ברשת הסקירה הכללית. כדי לבצע זאת, עליך להוסיף פונקציות מסוג listener של onClick
לפריטים ברשת RecyclerView
. לאחר מכן עליך לעבור אל הקטע החדש. הניווט על ידי הפעלת שינוי של LiveData
בViewModel
, כפי שעשית בקורסים האלה. אפשר גם להשתמש בפלאגין 'אזורים בטוחים' של רכיב הניווט כדי להעביר את המידע על MarsProperty
שנבחר מקטע הסקירה הכללית לקטע הקוד של הפרטים.
שלב 1: יוצרים את מודל תצוגת הפרטים ומעדכנים את פריסת הפרטים
בדומה לתהליך שבו נעשה שימוש במודל הסקירה הכללית ובמודלי התצוגה, כך אתם צריכים להטמיע עכשיו את מודל התצוגה ואת קובצי הפריסה עבור קטע הקוד.
- פתיחת
detail/DetailViewModel.kt
בדיוק כמו שקובצי Kotlin הקשורים לרשת כלולים בתיקייהnetwork
ובקובצי הסקירה הכללית ב-overview
, כך התיקייהdetail
מכילה את הקבצים המשויכים לתצוגת הפרטים. לידיעתך, מחלקהDetailViewModel
(ריקה כרגע) מקבלת את הערךmarsProperty
כפרמטר בבנייה.
class DetailViewModel( marsProperty: MarsProperty,
app: Application) : AndroidViewModel(app) {
}
- בתוך הגדרת הכיתה, יש להוסיף את
LiveData
לנכס המאדים שנבחר, כדי לחשוף את המידע הזה בתצוגת הפרטים. יש לפעול לפי הדפוס הרגיל של יצירתMutableLiveData
כדי לשמור את ה-MarsProperty
עצמו ולאחר מכן לחשוף את הנכס הגלוי לכול שלLiveData
.
יש לייבא אתandroidx.lifecycle.LiveData
ולייבא אתandroidx.lifecycle.MutableLiveData
לפי בקשה.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
get() = _selectedProperty
- יש ליצור בלוק מסוג
init {}
ולהגדיר את הערך של מאפיין ה-Mars שנבחר באמצעות אובייקטMarsProperty
מהבונה.
init {
_selectedProperty.value = marsProperty
}
- פותחים את
res/layout/fragment_detail.xml
ומחפשים את התמונה בתצוגת העיצוב.
זהו קובץ הפריסה של קטע הקוד. הוא מכילImageView
עבור התמונה הגדולה,TextView
עבור סוג הנכס (השכרה או מכירה) ו-TextView
עבור המחיר. לתשומת ליבכם, פריסת האילוץ מוקפת ב-ScrollView
כך שהיא תיגלל באופן אוטומטי אם התצוגה גדולה מדי לתצוגה, למשל כשהמשתמש צופה בה במצב פריסה לרוחב. - נכנסים לכרטיסיית טקסט לפריסה. בחלק העליון של הפריסה, ממש לפני הרכיב
<ScrollView>
, מוסיפים רכיב<data>
כדי לשייך את המודל של תצוגת הפרטים לפריסה.
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>
- יש להוסיף את המאפיין
app:imageUrl
לאלמנטImageView
. יש להגדיר אותו כ-imgSrcUrl
מהנכס שהוגדר בדגם התצוגה המפורטת.
בנוסף, גם המתאם המחייב שטוען תמונה באמצעות החלקה ישתמש כאן באופן אוטומטי כי המתאם צופה בכל המאפיינים שלapp:imageUrl
.
app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"
שלב 2: הגדרת ניווט במודל תצוגת הסקירה הכללית
כאשר המשתמש מקיש על תמונה במודל הסקירה הכללית, הוא צריך לנווט לניווט אל שבר שמציג פרטים על הפריט שנלחץ.
- פתיחת
overview/OverviewViewModel.kt
יש להוסיף נכסMutableLiveData
ב-_navigateToSelectedProperty
ולחשוף אותו עםLiveData
שלם.
כשה-LiveData
הזה משתנה לערך null, הניווט מופעל. (בקרוב תוסיפו את הקוד כדי לבחון את המשתנה הזה ולהפעיל את הניווט).
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
get() = _navigateToSelectedProperty
- בסוף הכיתה, מוסיפים שיטת
displayPropertyDetails()
שמגדירה _navigateToSelectedProperty
לנכס המאדים שנבחר.
fun displayPropertyDetails(marsProperty: MarsProperty) {
_navigateToSelectedProperty.value = marsProperty
}
- יש להוסיף שיטה
displayPropertyDetailsComplete()
שמחזירה את הערך של_navigateToSelectedProperty
. הפעולה הזו נדרשת כדי לסמן את מצב הניווט, וכדי שהניווט לא יופעל שוב כשהמשתמש יחזור מתצוגת הפרטים.
fun displayPropertyDetailsComplete() {
_navigateToSelectedProperty.value = null
}
שלב 3: הגדרת מאזינים לקליקים במתאם ובמקטע הרשת
- פתיחת
overview/PhotoGridAdapter.kt
בסוף הכיתה, יוצרים כיתה מותאמת אישית ב-OnClickListener
של למדה עם פרמטרmarsProperty
. בתוך הכיתה, מגדירים פונקצייתonClick()
שמוגדרת כפרמטר lambda.
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}
- יש לגלול למעלה אל הגדרת הכיתה עבור
PhotoGridAdapter
, ולהוסיף לנכס נכסOnClickListener
פרטי.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
- כדי להפוך תמונה לזמינה, יש להוסיף את
onClickListener
לפריט הרשת בשיטהonBindviewHolder()
. הגדרת האזנה לקליקים בין שיחות אלgetItem() and bind()
.
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
val marsProperty = getItem(position)
holder.itemView.setOnClickListener {
onClickListener.onClick(marsProperty)
}
holder.bind(marsProperty)
}
- פתיחת
overview/OverviewFragment.kt
בשיטהonCreateView()
, צריך להחליף את השורה שמפעילה את הנכס שלbinding.photosGrid.adapter
בשורה שמוצגת למטה.
הקוד הזה מוסיף את האובייקטPhotoGridAdapter.onClickListener
לבנייה שלPhotoGridAdapter
, ומתקשר אלviewModel.displayPropertyDetails()
עם האובייקט שלMarsProperty
שהועבר. הפעולה הזו תפעיל אתLiveData
במודל התצוגה של הניווט.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
viewModel.displayPropertyDetails(it)
})
שלב 4: משנים את תרשים הניווט והופכים את הנכס של Mars לנכס משותף
כשמשתמש מקיש על תמונה בתצוגת הסקירה הכללית, האפליקציה צריכה לעבור לקטע הפרטים ולעבור על הפרטים של נכס Mars שנבחר כדי שתצוגת הפרטים תוכל להציג את המידע הזה.
כרגע יש לך event listener מ-PhotoGridAdapter
לטיפול בהקשה, ודרך להפעיל את הניווט ממודל התצוגה. אך עדיין אין לך אובייקט MarsProperty
מועבר לקטע המידע. לשם כך, אתם משתמשים בפקודות בטוחה מרכיב הניווט.
- פתיחת
res/navigation/nav_graph.xml
לוחצים על הכרטיסייה טקסט כדי להציג את קוד ה-XML של תרשים הניווט. - בתוך האלמנט
<fragment>
עבור קטע הקוד, מוסיפים את הרכיב<argument>
שמוצג למטה. הארגומנט הזה, בשםselectedProperty
, מכיל את הסוגMarsProperty
.
<argument
android:name="selectedProperty"
app:argType="com.example.android.marsrealestate.network.MarsProperty"
/>
- הידור של האפליקציה. הניווט מציג שגיאה כי
MarsProperty
לא זמין להורדה. הממשקParcelable
מאפשר סידור של אובייקטים כך שהאובייקטים יוכלו לעבור בין מקטעים או פעילויות. במקרה זה, כדי שהנתונים בתוך אובייקטMarsProperty
יועברו לקטע הקוד של הפרטים באמצעות בטוח, הארגומנטים שלMarsProperty
חייבים להטמיע את הממשקParcelable
. החדשות הטובות הן ש-Kotlin מספקת קיצור דרך קל ליישום הממשק הזה. - פתיחת
network/MarsProperty.kt
צריך להוסיף את ההערה@Parcelize
להגדרת הכיתה.
כשמייבאים בקשהkotlinx.android.parcel.Parcelize
, מייבאים אותה.
ההערה@Parcelize
משתמשת בתוספים של Kotlin ל-Android כדי להטמיע באופן אוטומטי את השיטות בממשקParcelable
של הכיתה הזו. אין צורך לבצע פעולה נוספת!
@Parcelize
data class MarsProperty (
- יש לשנות את הגדרת הכיתה
MarsProperty
כדי להרחיב אתParcelable
.
יש לייבא אתandroid.os.Parcelable
לפי בקשה.
הגדרת הכיתהMarsProperty
נראית עכשיו:
@Parcelize
data class MarsProperty (
val id: String,
@Json(name = "img_src") val imgSrcUrl: String,
val type: String,
val price: Double) : Parcelable {
שלב 5: חיבור המקטעים
עדיין אינכם מנווטים – הניווט בפועל מקוטע. בשלב זה מוסיפים את הביטים האחרונים ליישום הניווט בין הסקירה הכללית לבין קטעי הקוד של הפרטים.
- פתיחת
overview/OverviewFragment.kt
ב-onCreateView()
, מתחת לשורות שמפעילים את המתאם של רשת התמונות, יש להוסיף את השורות שבהמשך כדי לראות אתnavigatedToSelectedProperty
מהמודל של תצוגת הסקירה הכללית.
יש לייבא אתandroidx.lifecycle.Observer
ולייבא אתandroidx.navigation.fragment.findNavController
לפי בקשה.
הצופה בודק אםMarsProperty
—it
בלאמדה – לא Null, ואם כן, הוא מקבל את בקר הניווט מהמקטע באמצעותfindNavController()
. יש להתקשר אלdisplayPropertyDetailsComplete()
כדי לבקש ממודל התצוגה לאפס אתLiveData
למצב null, כדי לא להפעיל שוב את הניווט בטעות כשהאפליקציה תחזיר אלOverviewFragment
.
viewModel.navigateToSelectedProperty.observe(this, Observer {
if ( null != it ) {
this.findNavController().navigate(
OverviewFragmentDirections.actionShowDetail(it))
viewModel.displayPropertyDetailsComplete()
}
})
- פתיחת
detail/DetailFragment.kt
יש להוסיף את השורה הזו מתחת לקריאה ב-setLifecycleOwner()
בשיטהonCreateView()
. שורה זו מקבלת את האובייקטMarsProperty
שנבחר מהקבוצות הבטוחות.
יש לשים לב לשימוש באופרטור ההצהרה Kotlin' (!!
). אםselectedProperty
לא שם, משהו נורא קרה ולמעשה ברצונך להעביר קוד מצביע. (בקוד הייצור, צריך לטפל בדרך זו בשגיאה).
val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty
- יש להוסיף את השורה הזו כדי לקבל
DetailViewModelFactory
חדש. צריך להשתמש בפונקציהDetailViewModelFactory
כדי לקבל מופע שלDetailViewModel
. האפליקציה למתחילים כוללת הטמעה שלDetailViewModelFactory
, לכן צריך לבצע אותה רק כאן.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)
- לבסוף, יש להוסיף את השורה הזו כדי לקבל
DetailViewModel
מהמפעל ולחבר את כל החלקים.
binding.viewModel = ViewModelProviders.of(
this, viewModelFactory).get(DetailViewModel::class.java)
- הידור והפעלה של האפליקציה והקש על תמונה של נכס Mars. קטע הקוד מופיע עבור פרטי הנכס הזה. מקישים על הלחצן 'הקודם' כדי לחזור לדף הסקירה הכללית ושמים לב שמסך הפרטים עדיין מעט צר. במשימה הבאה מסיימים להוסיף את נתוני הנכסים לדף הפרטים.
כרגע, דף הפרטים מציג רק את אותה תמונה של מאדים שאתם רגילים לראות בדף הסקירה הכללית. לקטגוריה MarsProperty
יש גם סוג נכס (השכרה או קנייה) ומחיר נכס. מסך הפרטים צריך לכלול את שני הערכים האלה, ומועיל אם הנכסים להשכרה ציינו שהמחיר היה ערך לחודש. LiveData
משתמש בטרנספורמציות במודל התצוגה כדי ליישם את שני הדברים האלה.
- פתיחת
res/values/strings.xml
הקוד למתחילים כולל משאבי מחרוזת, המוצגים בהמשך, כדי לעזור לכם ליצור את המחרוזות לתצוגת הפרטים. עבור המחיר, יש להשתמש במשאבdisplay_price_monthly_rental
או במשאבdisplay_price
, בהתאם לסוג הנכס.
<string name="type_rent">Rent</string>
<string name="type_sale">Sale</string>
<string name="display_type">For %s</string>
<string name="display_price_monthly_rental">$%,.0f/month</string>
<string name="display_price">$%,.0f</string>
- פתיחת
detail/DetailViewModel.kt
צריך להוסיף את הקוד שמופיע בחלק התחתון של הכיתה.
יש לייבא אתandroidx.lifecycle.Transformations
לפי בקשה.
הטרנספורמציה הזו בודקת אם הנכס שנבחר הוא השכרה, באמצעות אותה בדיקה מהמשימה הראשונה. אם הנכס מושכר, הטרנספורמציה בוחרת את המחרוזת המתאימה מהמשאבים עם מתגwhen {}
של Kotlin. שתי המחרוזות האלה דורשות מספר בסוף, כך שיש לשרשר לאחר מכן אתproperty.price
.
val displayPropertyPrice = Transformations.map(selectedProperty) {
app.applicationContext.getString(
when (it.isRental) {
true -> R.string.display_price_monthly_rental
false -> R.string.display_price
}, it.price)
}
- אפשר לייבא את הכיתה
R
שנוצרה כדי לקבל גישה למשאבי המחרוזת בפרויקט.
import com.example.android.marsrealestate.R
- לאחר השינוי של
displayPropertyPrice
, יש להוסיף את הקוד המוצג למטה. בטרנספורמציה הזו שרשורי כמה משאבי מחרוזת, לפי סוג הנכס – השכרה.
val displayPropertyType = Transformations.map(selectedProperty) {
app.applicationContext.getString(R.string.display_type,
app.applicationContext.getString(
when (it.isRental) {
true -> R.string.type_rent
false -> R.string.type_sale
}))
}
- פתיחת
res/layout/fragment_detail.xml
יש רק עוד דבר אחד לעשות, והוא לחייב את המחרוזות החדשות (שיצרת עם השינויים ב-LiveData
) לתצוגת הפרטים. כדי לעשות את זה, מגדירים את הערך של שדה הטקסט לטקסט של סוג הנכס ל-viewModel.displayPropertyType
ואת שדה הטקסט לטקסט של ערך מחיר ל-viewModel.displayPropertyPrice
.
<TextView
android:id="@+id/property_type_text"
...
android:text="@{viewModel.displayPropertyType}"
...
tools:text="To Rent" />
<TextView
android:id="@+id/price_value_text"
...
android:text="@{viewModel.displayPropertyPrice}"
...
tools:text="$100,000" />
- הידור והפעלה של האפליקציה. עכשיו כל נתוני הנכס מופיעים בדף הפרטים, בפורמט יפה.
פרויקט ב-Android Studio: MarsRealEstateFinal
ביטויי קישור
- שימוש בביטויי קישור בקובצי פריסת XML לביצוע פעולות פרוגרמטיות פשוטות, כמו בדיקות מתמטיות או בדיקות מותנות, בנתוני איגוד.
- כדי להפנות לכיתות בקובץ הפריסה, יש להשתמש בתג
<import>
שבתג<data>
.
אפשרויות שאילתה של שירות אינטרנט
- בקשות לשירותי אינטרנט יכולות לכלול פרמטרים אופציונליים.
- כדי לציין פרמטרים של שאילתות בבקשה, צריך להשתמש בהערה
@Query
בקטע Retrofit.
קורס אוניברסיטה:
התיעוד של מפתח Android:
- סקירה כללית של ViewModel
- סקירה כללית של LiveData
- מתאמים מחייבים
- פריסות וביטויים מחייבים
- ניווט
- התחלת השימוש ברכיב הניווט
- העברת הנתונים בין יעדים (תיאור גם של 'מצבי בטיחות')
Transformations
כיתהViewModelProvider
כיתהViewModelProvider.Factory
כיתה
אחר:
- החלקה
- סיווג שאילתה מחדש
- Kotlin's תוסף מחולל לחניה
בקטע הזה מפורטות מטלות שיעורי בית אפשריות לתלמידים שעובדים עם קוד Lab הזה, במסגרת קורס בהדרכת מורה. למורה יש אפשרות לבצע את הפעולות הבאות:
- אם צריך, מקצים שיעורי בית.
- ספרו לתלמידים איך מגישים מטלות בשיעורי בית.
- לתת ציונים למטלות שיעורי הבית.
המורים יכולים להשתמש בהצעות האלה כמה שפחות, ומומלץ להקצות להן כל שיעורי בית שדעתם מתאימה להם.
אם אתם עובדים בעצמכם על שיעור הקוד הזה, אתם מוזמנים להשתמש במטלות שיעורי הבית האלה כדי לבחון את הידע שלכם.
מענה על השאלות הבאות
שאלה 1
מה עושה התג <import>
בקובץ פריסת XML?
▬ לכלול קובץ פריסה אחד בקובץ אחר.
▸ הטמעת קוד Kotlin בקובץ הפריסה.
הוספה צריך לספק גישה לנכסים שקשורים לנתונים.
הוספה כאן אפשר להפנות לכיתות ולחברים בכיתה באמצעות ביטויים מחייבים.
שאלה 2
איך מוסיפים אפשרות לשאילתה בשיחה עם שירות אינטרנט של REST ב-Retrofit?
הוספה יש להוסיף את השאילתה לסוף כתובת ה-URL של הבקשה.
הוספה צריך להוסיף פרמטר לשאילתה כדי להפעיל את הבקשה, ולהוסיף הערות לפרמטר הזה באמצעות @Query
.
הוספה יש להשתמש בכיתה Query
כדי ליצור בקשה.
הוספה יש להשתמש בשיטה addQuery()
בכלי ליצירת רטרופיט.
להשתתפות בשיעור הבא:
קישורים למעבדות אחרות של הקוד בקורס הזה זמינים בדף הנחיתה של Android Kotlin Fundamentals Codelabs.