Android Kotlin 基礎知識 08.3 篩選網際網路資料並建立詳細資料檢視畫面

這個程式碼研究室是 Android Kotlin 基礎知識課程的一部分。如果您按部就班完成程式碼研究室,就能充分體驗到本課程的價值。所有課程程式碼研究室都列在 Android Kotlin 基礎知識程式碼研究室到達網頁

簡介

在本課程的先前程式碼研究室中,您已瞭解如何從網路服務取得火星房地產資料,以及如何建立具有格線版面的 RecyclerView,從該資料載入及顯示圖片。在本程式碼研究室中,您將實作篩選火星地產的功能,依據地產是否可供出租或購買來篩選,完成 MarsRealEstate 應用程式。您也可以建立詳細資料檢視畫面,讓使用者輕觸總覽中的房源相片時,看到該房源的詳細資料。

須知事項

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

課程內容

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

執行步驟

  • 修改 MarsRealEstate 應用程式,以錢幣符號圖示標示待售的火星地產 (與待出租地產區別)。
  • 使用總覽頁面的選項選單,建立網路服務要求,依類型篩選火星地產。
  • 為火星房地產建立詳細資料片段,透過導覽將該片段連結至總覽格線,並將房地產資料傳遞至該片段。

在本程式碼研究室 (和相關程式碼研究室) 中,您將使用名為 MarsRealEstate 的應用程式,顯示火星上的待售地產。這個應用程式會連線至網際網路伺服器,以擷取及顯示房地產資料,包括價格和房地產是否待售或待租等詳細資料。代表各個屬性的圖片是自 NASA 火星漫遊者擷取的火星實景相片。在先前的程式碼研究室中,您已建立 RecyclerView,並為所有房源相片設定格線版面配置:

在這個版本的應用程式中,您要處理房地產類型 (租賃或購買),並在格線版面配置中新增圖示,標示待售房地產:

修改應用程式的選項選單,篩選格線,只顯示待出租或待售的房地產:

最後,您要為個別地產建立詳細資料檢視畫面,並使用導覽功能將總覽格線上的圖示連結至該詳細資料片段:

到目前為止,您只使用了火星房地產資料中的房地產圖片網址。但您在 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 程式庫,將火星網路服務的原始 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. ImageViewandroid:layout_height 屬性變更為 match_parent,以填入新的父項 FrameLayout
android:layout_height="match_parent"
  1. FrameLayout 內,於第一個 <ImageView> 元素正下方新增第二個 <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. mars_property_type 圖片檢視區塊中加入 android:visibility 屬性。使用繫結運算式測試屬性型別,並將可見度指派給 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>
  1. 編譯並執行應用程式,並注意非出租的房源會顯示美元符號圖示。

目前,您的應用程式會在總覽格線中顯示所有火星地產。假設使用者在火星上尋找出租房源,如果能透過圖示指出哪些房源可供出售,會很有幫助,但頁面上仍有許多房源需要捲動瀏覽。在這項工作中,您要在總覽片段中新增選項選單,讓使用者只顯示出租房源、只顯示待售房源,或顯示所有房源。

如要完成這項工作,其中一種方法是測試總覽格線中每個 MarsProperty 的型別,然後只顯示相符的屬性。不過,實際的火星網路服務具有查詢參數或選項 (稱為 filter),可讓您只取得 rentbuy 類型的房地產。您可以在瀏覽器中使用這個篩選查詢和 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() 方法 (以及 Retrofit),要使用篩選器選項發出網路服務要求。每次呼叫 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. 編譯並執行應用程式。應用程式會啟動第一個總覽格線,其中包含所有房地產類型,以及以美元圖示標示的待售房地產。
  2. 從選項選單中選擇「租借」。屬性會重新載入,且不會顯示任何美元圖示。(系統只會顯示出租房源)。顯示畫面可能需要稍候片刻才會重新整理,只顯示已篩選的資源。
  3. 從選項選單中選擇「購買」。屬性會再次重新載入,且所有屬性都會顯示美元圖示。(只會顯示待售房源)。

現在您已擁有 Mars 屬性的捲動圖示格線,但現在要取得更多詳細資料。在這項工作中,您要新增詳細資料片段,顯示特定房源的詳細資料。詳細資料片段會顯示較大的圖片、價格和房源類型 (出租或出售)。

使用者輕觸總覽格線中的圖片時,系統會啟動這個片段。如要達成這個目標,您需要在 RecyclerView 格線項目中新增 onClick 監聽器,然後前往新的片段。您會觸發 ViewModel 中的 LiveData 變更來進行導覽,就像您在這些課程中所做的一樣。您也會使用 Navigation 元件的 Safe Args 外掛程式,將所選MarsProperty資訊從總覽片段傳遞至詳細資料片段。

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

與您用於總覽檢視模型和片段的程序類似,您現在需要實作詳細資料片段的檢視模型和版面配置檔案。

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

    視需要匯入 androidx.lifecycle.LiveDataandroidx.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. ImageView 元素中新增 app:imageUrl 屬性。將其設為檢視畫面模型所選屬性的 imgSrcUrl

    由於該轉接器會監控所有 app:imageUrl 屬性,因此系統也會在這裡自動使用透過 Glide 載入圖片的繫結轉接器。
 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. 新增 displayPropertyDetailsComplete() 方法,將 _navigateToSelectedProperty 的值設為空值。您需要這個項目來將導覽狀態標示為完成,並避免使用者從詳細資料檢視畫面返回時再次觸發導覽。
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 建構函式,並使用傳入的 MarsProperty 物件呼叫 viewModel.displayPropertyDetails()。這會觸發導覽檢視模型中的 LiveData
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
   viewModel.displayPropertyDetails(it)
})

步驟 4:修改導覽圖,並將 MarsProperty 設為可封送

使用者輕觸總覽格線中的相片時,應用程式應前往詳細資料片段,並傳遞所選火星房地產的詳細資料,以便詳細資料檢視畫面顯示該資訊。

目前您有一個來自 PhotoGridAdapter 的點擊事件監聽器,可處理輕觸動作,並提供從檢視模型觸發導覽的方法。但您尚未將 MarsProperty 物件傳遞至詳細資料片段。為此,您可以使用導覽元件的 Safe Args。

  1. 開啟 res/navigation/nav_graph.xml。按一下「Text」分頁標籤,即可查看導覽圖的 XML 程式碼。
  2. 在詳細資料片段的 <fragment> 元素中,新增下方顯示的 <argument> 元素。這個引數名為 selectedProperty,型別為 MarsProperty
<argument
   android:name="selectedProperty"
   app:argType="com.example.android.marsrealestate.network.MarsProperty"
   />
  1. 編譯應用程式。由於 MarsProperty「不可封送」,因此導覽會顯示錯誤。Parcelable 介面可讓物件序列化,因此物件資料可以在片段或活動之間傳遞。在這種情況下,如要透過 Safe Args 將 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.Observerandroidx.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 的非空值斷言運算子 (!!) 用法。如果沒有 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 Web 服務呼叫?

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

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

▢ 使用 Query 類別建構要求。

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

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

如要查看本課程其他程式碼研究室的連結,請參閱 Android Kotlin 基礎知識程式碼研究室登陸頁面