Android Kotlin 基礎課程 08.3 使用網際網路資料進行篩選及詳細檢視

本程式碼研究室是 Android Kotlin 基礎課程的一部分。使用程式碼研究室逐步完成程式碼課程後,您將能充分發揮本課程的潛能。所有課程程式碼研究室清單均列於 Android Kotlin 基礎程式碼研究室到達網頁

簡介

在上一堂課程中,本課程說明瞭如何從網路服務取得有關火星的房地產資料,以及如何建立具備格線版面配置的 RecyclerView,以載入及顯示這些資料的圖片。在這個程式碼研究室中,您將根據是否允許租看或購買,以篩選 MarsRealEstate 應用程式來篩選火星屬性。你也可以建立詳細視圖,這樣使用者輕觸總覽中的資源相片時,就會看到詳細屬性的詳細資料。

須知事項

  • 如何建立及使用片段。
  • 如何在片段之間瀏覽,並使用安全架構 (Gradle 外掛程式) 在片段之間傳送資料。
  • 如何使用架構元件,包括檢視模型、查看模型工廠、轉換和 LiveData
  • 如何從 REST 網路服務擷取 JSON 編碼資料,並使用 RetrofitMoshi 程式庫將該資料剖析為 Kotlin 物件。

您將會瞭解的內容

  • 如何在版面配置檔案中使用複雜的繫結運算式。
  • 如何透過查詢選項向網路服務發出 Retrofit 要求。

要執行的步驟

  • 修改 MarsRealEstate 應用程式,使用「美元符號」圖示標示待售的火星資產 (而非出租的物業)。
  • 使用總覽頁面上的選項選單建立網路服務要求,並依類型篩選火星屬性。
  • 為 Mars 屬性建立詳細片段,使用導覽功能將片段掛上總覽格線,然後將屬性資料傳送至該片段。

在這個程式碼研究室 (和相關的程式碼研究室中) 中,您可以使用名為 MarsRealEstate 的應用程式,在火星上展示待售房地產。這個應用程式會連線至網際網路伺服器,以擷取和顯示屬性資料,包括價格、是否販售或出租等詳細資料。每個資源代表的圖片都是從 NASA 所拍攝的火星漫遊的實景照片。在先前的程式碼研究室中,您已建立包含所有屬性相片的格狀版面配置的 RecyclerView

在這個版本的應用程式中,您需處理資源類型 (出租或購買),並在網格版面配置中加入圖示,以標記待售房地產:

您修改了應用程式的選項選單,以篩選格狀畫面,只顯示出租或銷售的屬性:

最後,您可以為個別資源建立詳細檢視,然後透過總覽,將總覽格線中的圖示連結至該詳細資料片段:

截至目前為止,您使用的 Mars 屬性資料中只有一部分是資源圖片的網址。不過,您在 MarsProperty 類別中定義的資源資料也包含 ID、價格和類型 (出租或銷售)。重新整理記憶中,以下是從網路服務取得的 JSON 資料片段:

{
   "price":8000000,
   "id":"424908",
   "type":"rent",
   "img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631290305226E03_DXXX.jpg"
},

在這項工作中,您會開始與火星的資源類型合作,在要銷售的總覽頁面中的屬性中加入美元符號圖片。

步驟 1:更新 MarsProperty 以納入類型

MarsProperty 類別可定義網路服務提供的各個屬性的資料結構。在先前的程式碼研究室中,您已使用 Moshi 程式庫將 Mars 網路服務的原始 JSON 回應剖析為個別的 MarsProperty 資料物件。

在這個步驟中,您會為 MarsProperty 類別新增一些邏輯,指出特定屬性是否屬於出租物 (亦即該類型是否為 "rent""buy" 字串)。您會將這個邏輯放在多個位置,所以最好在資料類別中使用這個邏輯,而不是複製資料。

  1. 從最後一個程式碼研究室開啟 MarsRealEstate 應用程式。(如果您沒有這個應用程式,可以下載 MarsRealEstateGrid)。
  2. 開啟 network/MarsProperty.kt。在 MarsProperty 類別定義中新增主體,並為 isRental 新增自訂 getter,若物件類型為 "rent",則傳回 true
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 版面配置中完全測試。

  1. 開啟 res/layout/grid_view_item.xml。這是 RecyclerView 格線內每個儲存格的版面配置檔案。這個檔案目前只包含屬性圖片的 <ImageView> 元素。
  2. <data> 元素中,為 View 類別新增 <import> 元素。當您要在版面配置檔案的資料繫結運算式中使用類別的元件時,就可以使用匯入功能。在這個範例中,您應要使用 View.GONEView.VISIBLE 常數,所以您需要存取 View 類別。
<import type="android.view.View"/>
  1. FrameLayout
<FrameLayout
   android:layout_width="match_parent"
   android:layout_height="170dp">
             <ImageView 
                    android:id="@+id/mars_image"
            ...
</FrameLayout>
  1. 針對 ImageView,請將 android:layout_height 屬性變更為 match_parent,以填入新的父項 FrameLayout
android:layout_height="match_parent"
  1. FrameLayout 底下的第一個元素下方新增第二個 <ImageView> 元素。請使用下方定義的定義。這張圖片顯示在格線項目右下角 (位於火星圖片的上方),並使用「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"/>
  1. android:visibility 屬性新增至 mars_property_type 圖片檢視。使用繫結運算式來測試資源類型,並將顯示設定指定為 View.GONE (出租) 或 View.VISIBLE (購買)。
 android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"

目前,你只看到版面配置中使用 <data> 元素中定義的個別變數。繫結運算式具有強大功能,可讓你直接在 XML 版面配置中執行測試和數學計算等作業。在這個案例中,您需要使用三元運算子 (?:) 來執行測試 (此物件是租車嗎?)。您只為一項結果提供真實結果 (用 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>
  1. 編譯並執行應用程式。請注意,非租賃的屬性具有美元符號圖示。

您的應用程式目前會在總覽格線中顯示「所有」火星屬性。假設有使用者在火星上買有房租的房源,請用圖示來表示有哪些房源適合出售,但網頁上還是有許多資源可供捲動瀏覽。在這項工作中,您必須在總覽片段中加入選項選單,讓使用者只顯示出租物、僅限銷售的物業或全部顯示。

要完成這項工作,其中一種方法就是在總覽格狀空間中測試每個 MarsProperty 的類型,然後只顯示相符的屬性。不過,實際的火星網路服務具有查詢參數或選項 (稱為 filter),可讓您取得 rent 類型或 buy 類型的屬性。您可以按照下列瀏覽器,在 realestate 網路服務網址中使用這個篩選器查詢:

https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buy

在這項工作中,您可以修改 MarsApiService 類別,將查詢選項新增至含有 Retrofit 的網路服務要求。然後,透過選項選單,使用該查詢選項重新下載所有火星屬性資料。您從網路服務收到的回應僅包含您感興趣的屬性,因此無需變更總覽格線的檢視顯示邏輯。

步驟 1:更新 Mars API 服務

如要變更要求,您必須重新瀏覽您在本系列中第一個程式碼研究室實作的 MarsApiService 類別。您必須修改類別來提供篩選 API。

  1. 開啟 network/MarsApiService.kt。在匯入的正下方,建立一個名為 MarsApiFilterenum,以定義與網路服務預期的查詢值相符的常數。
enum class MarsApiFilter(val value: String) {
   SHOW_RENT("rent"),
   SHOW_BUY("buy"),
   SHOW_ALL("all") }
  1. 修改 getProperties() 方法以取得篩選器查詢的字串輸入內容,並使用 @Query("filter") 對其輸入註解 (如下所示)。

    在系統提示時匯入 retrofit2.http.Query

    @Query 註解會通知 getProperties() 方法 (進而改寫),以透過篩選器選項提出網路服務要求。每次呼叫 getProperties() 時,要求網址都會包含 ?filter=type 部分,這可引導網路服務傳回符合該查詢的結果。
fun getProperties(@Query("filter") type: String):  

步驟 2:更新總覽檢視模式

您在 OverviewViewModelgetMarsRealEstateProperties() 方法中要求 MarsApiService 的資料。現在,您必須更新該要求,才能使用篩選器引數。

  1. 開啟 overview/OverviewViewModel.kt。由於您在上一個步驟中所做的變更,將會在 Android Studio 中看到錯誤。將 MarsApiFilter (可能的篩選器值的列舉) 新增為 getMarsRealEstateProperties() 呼叫的參數。

    收到要求時匯入 com.example.android.marsrealestate.network.MarsApiFilter
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
  1. 修改 Retrofit 服務中對 getProperties() 的呼叫,以字串的形式傳送篩選查詢。
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)
  1. init {} 區塊中,將 MarsApiFilter.SHOW_ALL 做為引數傳遞至 getMarsRealEstateProperties(),以便在應用程式初次載入時顯示所有屬性。
init {
   getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
  1. 在類別的結尾新增 updateFilter() 方法,該方法接受 MarsApiFilter 引數,並以該引數呼叫 getMarsRealEstateProperties()
fun updateFilter(filter: MarsApiFilter) {
   getMarsRealEstateProperties(filter)
}

步驟 3:將片段連結至選項選單

最後一步是將溢位選單連接至片段,以便在使用者選取選單選項時,呼叫檢視模型上的 updateFilter()

  1. 開啟 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>
  1. 開啟 overview/OverviewFragment.kt。在類別的結尾,執行 onOptionsItemSelected() 方法來處理選單項目選項。
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} 
  1. onOptionsItemSelected() 中,使用適當的篩選器在檢視模型上呼叫 updateFilter() 方法。使用 Kotlin when {} 區塊來切換選項。使用 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
}
  1. 編譯並執行應用程式。應用程式會啟動第一個總覽格線,其中包含所有屬性類型,以及有 1 個代表貨幣圖示的待售屬性。
  2. 從選項選單中選擇 [租看]。屬性會重新載入,但當中不會出現任何貨幣圖示。(只顯示出租資源)。您可能需要稍候片刻,讓螢幕重新整理,只顯示經過篩選的屬性。
  3. 從選項選單中選擇 [購買]。屬性會重新載入,而所有資源都會顯示為美元圖示。(只顯示待售資源)。

現在,您擁有火星屬性的圖示捲動捲軸,但現在該詳細說明瞭。在這項工作中,您會加入一個詳細片段,以顯示特定屬性的詳細資料。詳細資料片段會顯示較大的圖片、價格和資源類型,無論是出租或出售。

當使用者輕觸總覽格線中的圖片時,即會啟動這個片段。如要達成這個目的,您必須將 onClick 監聽器新增至 RecyclerView 格線項目,然後瀏覽到新片段。瀏覽「ViewModel」時,您必須觸發 LiveData 變更 (相關課程內容均已完成)。您也可以使用導覽元件外掛程式,將所選 MarsProperty 資訊從總覽片段傳送至詳細片段。

步驟 1:建立詳細資料視圖模型並更新詳細資料版面配置

就如同您對總覽檢視模型和片段的程序一樣,現在您也需要為詳細片段實作檢視模型和版面配置檔案。

  1. 開啟 detail/DetailViewModel.kt。與網路相關的 Kotlin 檔案一樣位於 network 資料夾和 overview 的總覽檔案中,detail 資料夾則包含與詳細資料檢視相關的檔案。請注意,DetailViewModel 類別 (目前為空白) 會使用 marsProperty 做為建構函式中的參數。
class DetailViewModel( marsProperty: MarsProperty,
                     app: Application) : AndroidViewModel(app) {
}
  1. 在類別定義中,為所選的 Mars 屬性新增 LiveData,讓詳細資訊顯示在詳細檢視畫面中。請按照一般模式建立 MutableLiveData 以保存 MarsProperty 本身,然後公開不可變更的公開 LiveData 屬性。

    在需要時匯入 androidx.lifecycle.LiveData 並匯入 androidx.lifecycle.MutableLiveData
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
   get() = _selectedProperty
  1. 建立一個 init {} 區塊,並使用建構函式中的 MarsProperty 物件設定選定的 Mars 屬性值。
    init {
        _selectedProperty.value = marsProperty
    }
  1. 開啟「res/layout/fragment_detail.xml」並在設計檢視模式中查看。

    此為詳細片段的版面配置檔案。內含大型相片的 ImageView、物業類型 (出租或銷售) 的 TextView 和價格的 TextView。請注意,限製版面配置會以 ScrollView 包覆,因此如果畫面過大 (例如使用者在橫向模式中觀看影片),就會自動捲動。
  2. 前往版面配置的「文字」分頁。在版面配置頂端,就在 <ScrollView> 元素之前,新增 <data> 元素,將詳細資料檢視模型與版面配置建立關聯。
<data>
   <variable
       name="viewModel"
       type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>
  1. app:imageUrl 屬性新增至 ImageView 元素。在檢視模式中選取此屬性即可設為 imgSrcUrl

    透過 Glide 載入圖片的繫結轉接程式也會自動在這裡使用,因為該轉接程式會監控所有 app:imageUrl 屬性。
 app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"

步驟 2:在總覽檢視模式中定義導覽

當使用者在總覽模型中輕觸相片時,系統應在片段中啟動瀏覽點擊項目的相關詳細資料。

  1. 開啟 overview/OverviewViewModel.kt。新增 _navigateToSelectedProperty MutableLiveData 屬性並透過不可變更的 LiveData 將其公開。

    當此 LiveData 變更為非空值時,即會觸發導覽。(不久之後,您就會加入程式碼來觀察這個變數並觸發導覽)。
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
   get() = _navigateToSelectedProperty
  1. 在類別的結尾,新增 displayPropertyDetails() 方法來將 _navigateToSelectedProperty 加入所選的 Mars 屬性。
fun displayPropertyDetails(marsProperty: MarsProperty) {
   _navigateToSelectedProperty.value = marsProperty
}
  1. 加入空值 _navigateToSelectedPropertydisplayPropertyDetailsComplete() 方法。您需要執行這項操作,才能將導航狀態標示為已完成,並避免使用者在詳細資料檢視中再次觸發導覽。
fun displayPropertyDetailsComplete() {
   _navigateToSelectedProperty.value = null
}

步驟 3:在格線轉接程式和片段中設定點擊事件監聽器

  1. 開啟 overview/PhotoGridAdapter.kt。在類別的結尾建立自訂 OnClickListener 類別,並擷取包含 marsProperty 參數的 lambda。在類別內,定義設為 lambda 參數的 onClick() 函式。
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
     fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}
  1. 捲動至「PhotoGridAdapter」的類別定義,並在建構函式中新增私人 OnClickListener 屬性。
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
       ListAdapter<MarsProperty,              
           PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
  1. onBindviewHolder() 方法的網格項目中加入 onClickListener,即可將相片設為可點擊。定義在呼叫 getItem() and bind() 之間的點擊事件監聽器。
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
   val marsProperty = getItem(position)
   holder.itemView.setOnClickListener {
       onClickListener.onClick(marsProperty)
   }
   holder.bind(marsProperty)
}
  1. 開啟 overview/OverviewFragment.kt。在 onCreateView() 方法中,將初始化 binding.photosGrid.adapter 屬性的那一行替換為下列幾行。

    這段程式碼會將 PhotoGridAdapter.onClickListener 物件新增至 PhotoGridAdapter 建構函式,並呼叫 viewModel.displayPropertyDetails() 和傳遞的 MarsProperty 物件。這會在導航的檢視模式中觸發 LiveData
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
   viewModel.displayPropertyDetails(it)
})

步驟 4:修改導覽圖表,並調整 MarsProperty 的屬性

當使用者在總覽格線中輕觸相片時,應用程式應該瀏覽至詳細資料片段,並且傳遞所選 Mars 屬性的詳細資料,讓詳細資料檢視畫面能顯示相關資訊。

現在,「PhotoGridAdapter」有一個點擊事件監聽器可用來處理輕觸操作,以及從檢視模型觸發導覽的方法。但您尚未將 MarsProperty 物件傳遞至詳細資料片段。請在導覽元件中使用安全架構。

  1. 開啟 res/navigation/nav_graph.xml。按一下 [文字] 標籤即可查看導覽圖表的 XML 程式碼。
  2. 在詳細資料片段的 <fragment> 元素中,新增下方顯示的 <argument> 元素。此引數稱為 selectedProperty,其類型為 MarsProperty
<argument
   android:name="selectedProperty"
   app:argType="com.example.android.marsrealestate.network.MarsProperty"
   />
  1. 編譯應用程式。由於 MarsProperty 沒有可剖析的錯誤,因此導覽將會顯示錯誤訊息。Parcelable 介面可讓物件序列化,以便讓物件在片段或活動之間來回傳送。在這個情況下,要通過安全聲明MarsProperty對象內的數據,MarsProperty必須執行Parcelable界面。好消息是 Kotlin 提供了一個簡單的捷徑來實作該介面。
  2. 開啟 network/MarsProperty.kt。在類別定義中加入 @Parcelize 註解。

    要求時匯入 kotlinx.android.parcel.Parcelize

    @Parcelize 註解會使用 Kotlin Android 擴充功能,針對這個類別自動在 Parcelable 介面中實作方法。您無須採取其他動作!
@Parcelize
data class MarsProperty (
  1. 變更 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:連接片段

您仍在瀏覽,因為實際的瀏覽作業會位於片段中。在這個步驟中,您會新增最後一個位元來實作總覽和詳細片段之間的導覽。

  1. 開啟 overview/OverviewFragment.kt。在 onCreateView() 中,在初始化相片格狀轉接程式的線條下方,加入下列幾行即可從總覽檢視模型觀察 navigatedToSelectedProperty

    在需要時匯入 androidx.lifecycle.Observer 並匯入 androidx.navigation.fragment.findNavController

    觀測器會測試 MarsProperty (在 lambda 中的 it) 是否為空值;如果是的話,則會透過 findNavController() 從片段取得導覽控制器。呼叫 displayPropertyDetailsComplete() 要求檢視模型將 LiveData 重設為空值,因此當應用程式返回 OverviewFragment 時,不會意外觸發導航程序。
viewModel.navigateToSelectedProperty.observe(this, Observer {
   if ( null != it ) {   
      this.findNavController().navigate(
              OverviewFragmentDirections.actionShowDetail(it))             
      viewModel.displayPropertyDetailsComplete()
   }
})
  1. 開啟 detail/DetailFragment.kt。在 onCreateView() 方法的呼叫 setLifecycleOwner() 下方新增這一行。這一行程式碼會從「Safe Args」中取得所選的 MarsProperty 物件。

    請注意,使用 Kotlin 時不是使用 null 的斷言運算子 (!!)。如果 selectedProperty 不存在,代表發生了問題,您實際卻希望程式碼可以傳回一個空值。(在實際工作環境程式碼中,您應以某種方式處理這個錯誤)。
 val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty
  1. 新增這一行即可取得新的 DetailViewModelFactory。您將使用 DetailViewModelFactory 取得 DetailViewModel 的執行個體。啟動應用程式包含 DetailViewModelFactory 的實作,因此您只需要在這裡初始化應用程式。
val viewModelFactory = DetailViewModelFactory(marsProperty, application)
  1. 最後,加入這一行即可從工廠取得 DetailViewModel,並且連接所有零件。
      binding.viewModel = ViewModelProviders.of(
                this, viewModelFactory).get(DetailViewModel::class.java)
  1. 編譯並執行應用程式,然後輕觸任何火星屬性相片。這樣即可看到該資源的詳細資料詳情片段。輕觸 [返回] 按鈕即可返回總覽頁面,並注意到詳細資訊畫面仍是稀疏畫面。您會在下一個工作中,將屬性資料新增至該詳細資料頁面。

現在,詳細資料頁面只會顯示與總覽頁面上相同的火星相片。「MarsProperty」類別也有資源類型 (出租或購買) 和房源價格。詳細資料畫面應包含這兩個值;如果出租屬性指出價格是每月價格,則這項資訊十分有用。您可以在檢視模型中使用 LiveData 轉換來同時執行這兩項操作。

  1. 開啟 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>
  1. 開啟 detail/DetailViewModel.kt。在課程底部加入下方顯示的代碼。

    如果系統要求,請匯入 androidx.lifecycle.Transformations

    此轉換會使用第一項工作使用的相同測試來測試所選資源是否為租屋。如果屬性是租金,則轉換作業會從含有 Kotlin when {} 開關的資源中選擇適當的字串。這兩個字串的結尾都需要有數字,因此之後可以將 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)
}
  1. 匯入產生的 R 類別,以便存取專案中的字串資源。
import com.example.android.marsrealestate.R
  1. 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
                   }))
}
  1. 開啟 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" />
  1. 請編譯並執行應用程式。現在所有屬性資料都顯示在詳細資訊頁面上,格式正確。

Android Studio 專案:MarsRealEstateFinal

繫結運算式

  • 您可以在 XML 版面配置檔案中使用繫結運算式,對已繫結的資料執行簡單的程式輔助作業,例如數學或條件測試。
  • 如要參照版面配置檔案中的類別,請使用 <data> 標記內的 <import> 標記。

網路服務查詢選項

  • 對網路服務的要求可以包含選用參數。
  • 如要在要求中指定查詢參數,請使用 Retrofit 中的 @Query 註解。

Udacity 課程:

Android 開發人員說明文件:

其他:

這個部分會列出在代碼研究室中,受老師主導的課程作業的可能學生作業。由老師自行決定要執行下列動作:

  • 視需要指派家庭作業。
  • 告知學生如何提交家庭作業。
  • 批改家庭作業。

老師可視需要使用這些建議,並視情況指派其他合適的家庭作業。

如果您是自行操作本程式碼研究室,歡迎透過這些家庭作業來測試自己的知識。

回答這些問題

第 1 題

XML 版面配置檔案中的 <import> 標記有什麼作用?

▢ 在不同版面配置中納入一個版面配置檔案。

▢ 將 Kotlin 程式碼嵌入版面配置檔案。

▢ 提供資料繫結屬性的存取權。

▢ 可在繫結運算式中參照類別和類別成員。

第 2 題

如何將查詢選項新增至 Retrofit 中的 REST 網路服務呼叫?

▢ 將查詢附加到要求網址的結尾。

▢ 將查詢的參數新增至發出要求的函式,並以 @Query 為該參數加上註解。

▢ 使用 Query 類別建立要求。

▢ 使用 Retrofit 建構工具中的 addQuery() 方法。

開始下一門課程:9.1:存放區

如要瞭解本課程中其他程式碼研究室的連結,請參閱 Android Kotlin 基礎程式碼程式碼到達網頁