Codelab ini adalah bagian dari kursus Dasar-Dasar Android Kotlin. Anda akan mendapatkan manfaat maksimal dari kursus ini jika menyelesaikan codelab secara berurutan. Semua codelab kursus tercantum di halaman landing codelab Dasar-Dasar Android Kotlin.
Pengantar
Dalam codelab sebelumnya untuk pelajaran ini, Anda telah mempelajari cara mendapatkan data tentang real estate di Mars dari layanan web, dan cara membuat RecyclerView dengan tata letak petak untuk memuat dan menampilkan gambar dari data tersebut. Dalam codelab ini, Anda akan menyelesaikan aplikasi MarsRealEstate dengan menerapkan kemampuan untuk memfilter properti Mars berdasarkan ketersediaannya untuk disewa atau dibeli. Anda juga membuat tampilan detail sehingga jika pengguna mengetuk foto properti di ringkasan, mereka akan melihat tampilan detail dengan detail tentang properti tersebut.
Yang harus sudah Anda ketahui
- Cara membuat dan menggunakan fragmen.
- Cara bernavigasi antar-fragmen dan menggunakan Safe Args (plugin Gradle) untuk meneruskan data antar-fragmen.
- Cara menggunakan komponen arsitektur termasuk model tampilan, factory model tampilan, transformasi, dan
LiveData. - Cara mengambil data yang dienkode JSON dari layanan web REST dan mengurai data tersebut ke dalam objek Kotlin dengan library Retrofit dan Moshi.
Yang akan Anda pelajari
- Cara menggunakan ekspresi binding yang kompleks dalam file tata letak.
- Cara membuat permintaan Retrofit ke layanan web dengan opsi kueri.
Yang akan Anda lakukan
- Ubah aplikasi MarsRealEstate untuk menandai properti Mars yang dijual (bukan yang disewakan) dengan ikon tanda dolar.
- Gunakan menu opsi di halaman ringkasan untuk membuat permintaan layanan web yang memfilter properti Mars menurut jenisnya.
- Buat fragmen detail untuk properti Mars, hubungkan fragmen tersebut ke petak ringkasan dengan navigasi, dan teruskan data properti ke fragmen tersebut.
Dalam codelab ini (dan codelab terkait), Anda akan menggunakan aplikasi bernama MarsRealEstate, yang menampilkan properti yang dijual di Mars. Aplikasi ini terhubung ke server internet untuk mengambil dan menampilkan data properti, termasuk detail seperti harga dan apakah properti tersedia untuk dijual atau disewakan. Gambar yang merepresentasikan setiap properti adalah foto kehidupan nyata dari Mars yang diambil dari penjelajah Mars NASA. Dalam codelab sebelumnya, Anda membuat RecyclerView dengan tata letak petak untuk semua foto properti:

Dalam versi aplikasi ini, Anda akan menangani jenis properti (sewa versus beli) dan menambahkan ikon ke tata letak petak untuk menandai properti yang dijual:

Anda mengubah menu opsi aplikasi untuk memfilter petak guna menampilkan hanya properti yang disewakan atau dijual:

Terakhir, Anda akan membuat tampilan detail untuk setiap properti, dan menghubungkan ikon di petak ringkasan ke fragmen detail tersebut dengan navigasi:

Hingga saat ini, satu-satunya bagian data properti Mars yang telah Anda gunakan adalah URL untuk gambar properti. Namun, data properti—yang Anda tentukan di class MarsProperty—juga mencakup ID, harga, dan jenis (sewa atau dijual). Untuk menyegarkan ingatan Anda, berikut cuplikan data JSON yang Anda dapatkan dari layanan web:
{
"price":8000000,
"id":"424908",
"type":"rent",
"img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631290305226E03_DXXX.jpg"
},Dalam tugas ini, Anda akan mulai menggunakan jenis properti Mars untuk menambahkan gambar tanda dolar ke properti di halaman ringkasan yang dijual.
Langkah 1: Perbarui MarsProperty untuk menyertakan jenis
Class MarsProperty menentukan struktur data untuk setiap properti yang disediakan oleh layanan web. Dalam codelab sebelumnya, Anda menggunakan library Moshi untuk mengurai respons JSON mentah dari layanan web Mars menjadi objek data MarsProperty individual.
Pada langkah ini, Anda akan menambahkan beberapa logika ke class MarsProperty untuk menunjukkan apakah properti disewakan atau tidak (yaitu, apakah jenisnya adalah string "rent" atau "buy"). Anda akan menggunakan logika ini di lebih dari satu tempat, jadi lebih baik jika logika ini ada di sini dalam class data daripada direplikasi.
- Buka aplikasi MarsRealEstate dari codelab terakhir. (Anda dapat mendownload MarsRealEstateGrid jika tidak memiliki aplikasi.)
- Buka
network/MarsProperty.kt. Tambahkan isi ke definisi classMarsProperty, dan tambahkan getter kustom untukisRentalyang menampilkantruejika objek berjenis"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"
}Langkah 2: Perbarui tata letak item petak
Sekarang Anda memperbarui tata letak item untuk petak gambar guna menampilkan drawable tanda dolar hanya pada gambar properti yang dijual:

Dengan ekspresi data binding, Anda dapat melakukan pengujian ini sepenuhnya di tata letak XML untuk item petak.
- Buka
res/layout/grid_view_item.xml. Ini adalah file tata letak untuk setiap sel dalam tata letak petak untukRecyclerView. Saat ini, file hanya berisi elemen<ImageView>untuk gambar properti. - Di dalam elemen
<data>, tambahkan elemen<import>untuk classView. Anda menggunakan impor saat ingin menggunakan komponen class di dalam ekspresi data binding dalam file tata letak. Dalam hal ini, Anda akan menggunakan konstantaView.GONEdanView.VISIBLE, sehingga Anda memerlukan akses ke classView.
<import type="android.view.View"/>- Kelilingi seluruh tampilan gambar dengan
FrameLayout, agar drawable tanda dolar dapat ditumpuk di atas gambar properti.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ImageView
android:id="@+id/mars_image"
...
</FrameLayout>- Untuk
ImageView, ubah atributandroid:layout_heightmenjadimatch_parent, untuk mengisi induk baruFrameLayout.
android:layout_height="match_parent"- Tambahkan elemen
<ImageView>kedua tepat di bawah elemen pertama, di dalamFrameLayout. Gunakan definisi yang ditunjukkan di bawah. Gambar ini muncul di pojok kanan bawah item petak, di atas gambar Mars, dan menggunakan drawable yang ditentukan dalamres/drawable/ic_for_sale_outline.xmluntuk ikon tanda dolar.
<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"/>- Tambahkan atribut
android:visibilityke tampilan gambarmars_property_type. Gunakan ekspresi pengikatan untuk menguji jenis properti, dan tetapkan visibilitas keView.GONE(untuk rental) atauView.VISIBLE(untuk pembelian).
android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"Hingga saat ini, Anda hanya melihat ekspresi binding dalam tata letak yang menggunakan variabel individual yang ditentukan dalam elemen <data>. Ekspresi binding sangat canggih dan memungkinkan Anda melakukan operasi seperti pengujian dan penghitungan matematika sepenuhnya dalam tata letak XML. Dalam hal ini, Anda menggunakan operator ternary (?:) untuk melakukan pengujian (apakah objek ini adalah objek sewa?). Anda memberikan satu hasil untuk benar (sembunyikan ikon tanda dolar dengan View.GONE) dan hasil lainnya untuk salah (tampilkan ikon tersebut dengan View.VISIBLE).
File grid_view_item.xml lengkap yang baru ditampilkan di bawah:
<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>- Kompilasi dan jalankan aplikasi, lalu perhatikan bahwa properti yang bukan properti sewa memiliki ikon tanda dolar.

Saat ini, aplikasi Anda menampilkan semua properti Mars dalam petak ringkasan. Jika pengguna berbelanja properti sewa di Mars, ikon untuk menunjukkan properti yang tersedia untuk dijual akan berguna, tetapi masih banyak properti yang harus di-scroll di halaman. Dalam tugas ini, Anda akan menambahkan menu opsi ke fragmen ringkasan yang memungkinkan pengguna menampilkan hanya properti sewa, hanya properti dijual, atau menampilkan semua.

Salah satu cara untuk menyelesaikan tugas ini adalah dengan menguji jenis untuk setiap MarsProperty di petak ringkasan dan hanya menampilkan properti yang cocok. Namun, layanan web Mars yang sebenarnya memiliki parameter atau opsi kueri (disebut filter) yang memungkinkan Anda hanya mendapatkan properti jenis rent atau jenis buy. Anda dapat menggunakan kueri filter ini dengan URL layanan web realestate di browser seperti ini:
https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buyDalam tugas ini, Anda akan mengubah class MarsApiService untuk menambahkan opsi kueri ke permintaan layanan web dengan Retrofit. Kemudian, Anda menghubungkan menu opsi untuk mendownload ulang semua data properti Mars menggunakan opsi kueri tersebut. Karena respons yang Anda dapatkan dari layanan web hanya berisi properti yang Anda minati, Anda tidak perlu mengubah logika tampilan untuk petak ringkasan sama sekali.
Langkah 1: Perbarui layanan Mars API
Untuk mengubah permintaan, Anda perlu membuka kembali class MarsApiService yang Anda terapkan di codelab pertama dalam seri ini. Anda mengubah class untuk menyediakan API pemfilteran.
- Buka
network/MarsApiService.kt. Tepat di bawah impor, buatenumbernamaMarsApiFilteruntuk menentukan konstanta yang cocok dengan nilai kueri yang diharapkan oleh layanan web.
enum class MarsApiFilter(val value: String) {
SHOW_RENT("rent"),
SHOW_BUY("buy"),
SHOW_ALL("all") }- Ubah metode
getProperties()untuk mengambil input string untuk kueri filter, dan beri anotasi pada input tersebut dengan@Query("filter"), seperti yang ditunjukkan di bawah.
Imporretrofit2.http.Querybila diminta.
Anotasi@Querymemberi tahu metodegetProperties()(dan dengan demikian Retrofit) untuk membuat permintaan layanan web dengan opsi filter. Setiap kaligetProperties()dipanggil, URL permintaan akan menyertakan bagian?filter=type, yang mengarahkan layanan web untuk merespons dengan hasil yang cocok dengan kueri tersebut.
fun getProperties(@Query("filter") type: String): Langkah 2: Perbarui model tampilan ringkasan
Anda meminta data dari MarsApiService dalam metode getMarsRealEstateProperties() di OverviewViewModel. Sekarang Anda perlu memperbarui permintaan tersebut untuk mengambil argumen filter.
- Buka
overview/OverviewViewModel.kt. Anda akan melihat error di Android Studio karena perubahan yang Anda buat di langkah sebelumnya. TambahkanMarsApiFilter(enum kemungkinan nilai filter) sebagai parameter ke panggilangetMarsRealEstateProperties().
Imporcom.example.android.marsrealestate.network.MarsApiFilterbila diminta.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {- Ubah panggilan ke
getProperties()di layanan Retrofit untuk meneruskan kueri filter tersebut sebagai string.
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)- Di blok
init {}, teruskanMarsApiFilter.SHOW_ALLsebagai argumen kegetMarsRealEstateProperties(), untuk menampilkan semua properti saat aplikasi pertama kali dimuat.
init {
getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}- Di akhir class, tambahkan metode
updateFilter()yang menggunakan argumenMarsApiFilterdan memanggilgetMarsRealEstateProperties()dengan argumen tersebut.
fun updateFilter(filter: MarsApiFilter) {
getMarsRealEstateProperties(filter)
}Langkah 3: Hubungkan fragmen ke menu opsi
Langkah terakhir adalah menghubungkan menu tambahan ke fragmen untuk memanggil updateFilter() di model tampilan saat pengguna memilih opsi menu.
- Buka
res/menu/overflow_menu.xml. Aplikasi MarsRealEstate memiliki menu tambahan yang sudah ada dan menyediakan tiga opsi yang tersedia: menampilkan semua properti, hanya menampilkan properti sewa, dan hanya menampilkan properti yang dijual.
<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>- Buka
overview/OverviewFragment.kt. Di akhir class, terapkan metodeonOptionsItemSelected()untuk menangani pilihan item menu.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} - Di
onOptionsItemSelected(), panggil metodeupdateFilter()pada model tampilan dengan filter yang sesuai. Gunakan blokwhen {}Kotlin untuk beralih antar-opsi. GunakanMarsApiFilter.SHOW_ALLuntuk nilai filter default. Tampilkantrue, karena Anda telah menangani item menu. ImporMarsApiFilter(com.example.android.marsrealestate.network.MarsApiFilter) bila diminta. MetodeonOptionsItemSelected()lengkap ditampilkan di bawah.
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
}- Kompilasi dan jalankan aplikasi. Aplikasi meluncurkan petak ringkasan pertama dengan semua jenis properti dan properti yang dijual ditandai dengan ikon dolar.
- Pilih Sewa dari menu opsi. Properti dimuat ulang dan tidak ada yang muncul dengan ikon dolar. (Hanya properti rental yang ditampilkan.) Anda mungkin harus menunggu beberapa saat hingga tampilan dimuat ulang untuk hanya menampilkan properti yang difilter.
- Pilih Beli dari menu opsi. Properti dimuat ulang, dan semuanya muncul dengan ikon dolar. (Hanya properti yang dijual yang ditampilkan.)
Sekarang Anda memiliki petak ikon yang dapat di-scroll untuk properti Mars, tetapi sekarang saatnya mendapatkan detail selengkapnya. Dalam tugas ini, Anda akan menambahkan fragmen detail untuk menampilkan detail properti tertentu. Fragmen detail akan menampilkan gambar yang lebih besar, harga, dan jenis properti—apakah disewakan atau dijual.

Fragmen ini diluncurkan saat pengguna mengetuk gambar di petak ringkasan. Untuk melakukannya, Anda perlu menambahkan pemroses onClick ke item petak RecyclerView, lalu membuka fragmen baru. Anda berpindah bagian dengan memicu perubahan LiveData di ViewModel, seperti yang telah Anda lakukan di seluruh pelajaran ini. Anda juga menggunakan plugin Safe Args komponen Navigation untuk meneruskan informasi MarsProperty yang dipilih dari fragmen ringkasan ke fragmen detail.
Langkah 1: Buat model tampilan detail dan perbarui tata letak detail
Mirip dengan proses yang Anda gunakan untuk model tampilan dan fragmen ringkasan, Anda sekarang perlu menerapkan model tampilan dan file tata letak untuk fragmen detail.
- Buka
detail/DetailViewModel.kt. Sama seperti file Kotlin terkait jaringan yang ada di foldernetworkdan file ringkasan dioverview, folderdetailberisi file yang terkait dengan tampilan detail. Perhatikan bahwa classDetailViewModel(saat ini kosong) menggunakanmarsPropertysebagai parameter dalam konstruktor.
class DetailViewModel( marsProperty: MarsProperty,
app: Application) : AndroidViewModel(app) {
}- Di dalam definisi class, tambahkan
LiveDatauntuk properti Mars yang dipilih, untuk menampilkan informasi tersebut ke tampilan detail. Ikuti pola biasa dalam membuatMutableLiveDatauntuk menyimpanMarsPropertyitu sendiri, lalu ekspos propertiLiveDatapublik yang tidak dapat diubah.
Imporandroidx.lifecycle.LiveDatadan imporandroidx.lifecycle.MutableLiveDatabila diminta.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
get() = _selectedProperty- Buat blok
init {}dan tetapkan nilai properti Mars yang dipilih dengan objekMarsPropertydari konstruktor.
init {
_selectedProperty.value = marsProperty
}- Buka
res/layout/fragment_detail.xmldan lihat dalam tampilan desain.
Ini adalah file tata letak untuk fragmen detail. CSS ini berisiImageViewuntuk foto besar,TextViewuntuk jenis properti (sewa atau jual), danTextViewuntuk harga. Perhatikan bahwa tata letak batasan dibungkus denganScrollViewsehingga akan otomatis men-scroll jika tampilan terlalu besar untuk layar, misalnya saat pengguna melihatnya dalam mode lanskap. - Buka tab Teks untuk tata letak. Di bagian atas tata letak, tepat sebelum elemen
<ScrollView>, tambahkan elemen<data>untuk mengaitkan model tampilan detail dengan tata letak.
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>- Tambahkan atribut
app:imageUrlke elemenImageView. Setel keimgSrcUrldari properti yang dipilih model tampilan.
Adaptor binding yang memuat gambar menggunakan Glide juga akan otomatis digunakan di sini, karena adaptor tersebut memantau semua atributapp:imageUrl.
app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"Langkah 2: Tentukan navigasi dalam model tampilan ringkasan
Saat pengguna mengetuk foto dalam model ringkasan, hal ini akan memicu navigasi ke fragmen yang menampilkan detail tentang item yang diklik.
- Buka
overview/OverviewViewModel.kt. Tambahkan properti_navigateToSelectedPropertyMutableLiveDatadan ekspos denganLiveDatayang tidak dapat diubah.
SaatLiveDataini berubah menjadi non-null, navigasi akan dipicu. (Sebentar lagi Anda akan menambahkan kode untuk mengamati variabel ini dan memicu navigasi.)
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
get() = _navigateToSelectedProperty- Di akhir class, tambahkan metode
displayPropertyDetails()yang menyetel _navigateToSelectedPropertyke properti Mars yang dipilih.
fun displayPropertyDetails(marsProperty: MarsProperty) {
_navigateToSelectedProperty.value = marsProperty
}- Tambahkan metode
displayPropertyDetailsComplete()yang membatalkan nilai_navigateToSelectedProperty. Anda memerlukan ini untuk menandai status navigasi sebagai selesai, dan untuk menghindari navigasi dipicu lagi saat pengguna kembali dari tampilan detail.
fun displayPropertyDetailsComplete() {
_navigateToSelectedProperty.value = null
}Langkah 3: Siapkan pemroses klik di adaptor dan fragmen petak
- Buka
overview/PhotoGridAdapter.kt. Di akhir class, buat classOnClickListenerkustom yang menggunakan lambda dengan parametermarsProperty. Di dalam class, tentukan fungsionClick()yang ditetapkan ke parameter lambda.
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}- Scroll ke atas ke definisi class untuk
PhotoGridAdapter, lalu tambahkan propertiOnClickListenerpribadi ke konstruktor.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {- Buat foto dapat diklik dengan menambahkan
onClickListenerke item petak dalam metodeonBindviewHolder(). Tentukan pemroses klik di antara panggilan kegetItem() and bind().
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
val marsProperty = getItem(position)
holder.itemView.setOnClickListener {
onClickListener.onClick(marsProperty)
}
holder.bind(marsProperty)
}- Buka
overview/OverviewFragment.kt. Dalam metodeonCreateView(), ganti baris yang menginisialisasi propertibinding.photosGrid.adapterdengan baris yang ditampilkan di bawah.
Kode ini menambahkan objekPhotoGridAdapter.onClickListenerke konstruktorPhotoGridAdapter, dan memanggilviewModel.displayPropertyDetails()dengan objekMarsPropertyyang diteruskan. Hal ini memicuLiveDatadi model tampilan untuk navigasi.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
viewModel.displayPropertyDetails(it)
})Langkah 4: Ubah grafik navigasi dan jadikan MarsProperty dapat di-parcel
Saat pengguna mengetuk foto di petak ringkasan, aplikasi harus membuka fragmen detail dan meneruskan detail properti Mars yang dipilih sehingga tampilan detail dapat menampilkan informasi tersebut.

Saat ini Anda memiliki pemroses klik dari PhotoGridAdapter untuk menangani ketukan, dan cara untuk memicu navigasi dari model tampilan. Namun, Anda belum memiliki objek MarsProperty yang diteruskan ke fragmen detail. Untuk itu, Anda menggunakan Safe Args dari komponen navigasi.
- Buka
res/navigation/nav_graph.xml. Klik tab Text untuk melihat kode XML untuk grafik navigasi. - Di dalam elemen
<fragment>untuk fragmen detail, tambahkan elemen<argument>yang ditunjukkan di bawah. Argumen ini, yang disebutselectedProperty, memiliki jenisMarsProperty.
<argument
android:name="selectedProperty"
app:argType="com.example.android.marsrealestate.network.MarsProperty"
/>- Kompilasi aplikasi. Navigasi menampilkan error karena
MarsPropertytidak dapat parcelable. AntarmukaParcelablememungkinkan objek diserialisasi, sehingga data objek dapat diteruskan antar-fragmen atau aktivitas. Dalam hal ini, agar data di dalam objekMarsPropertyditeruskan ke fragmen detail melalui Safe Args,MarsPropertyharus menerapkan antarmukaParcelable. Kabar baiknya adalah Kotlin menyediakan pintasan mudah untuk menerapkan antarmuka tersebut. - Buka
network/MarsProperty.kt. Tambahkan anotasi@Parcelizeke definisi class.
Imporkotlinx.android.parcel.Parcelizejika diminta.
Anotasi@Parcelizemenggunakan ekstensi Android Kotlin untuk otomatis menerapkan metode di antarmukaParcelableuntuk class ini. Anda tidak perlu melakukan apa pun.
@Parcelize
data class MarsProperty (- Ubah definisi class
MarsPropertyuntuk memperluasParcelable.
Imporandroid.os.Parcelablejika diminta.
Definisi classMarsPropertysekarang terlihat seperti ini:
@Parcelize
data class MarsProperty (
val id: String,
@Json(name = "img_src") val imgSrcUrl: String,
val type: String,
val price: Double) : Parcelable {Langkah 5: Hubungkan fragmen
Anda masih belum melakukan navigasi—navigasi sebenarnya terjadi di fragmen. Pada langkah ini, Anda akan menambahkan bagian terakhir untuk mengimplementasikan navigasi antara fragmen ringkasan dan detail.
- Buka
overview/OverviewFragment.kt. DionCreateView(), di bawah baris yang menginisialisasi adaptor petak foto, tambahkan baris yang ditunjukkan di bawah untuk mengamatinavigatedToSelectedPropertydari model tampilan ringkasan.
Imporandroidx.lifecycle.Observerdan imporandroidx.navigation.fragment.findNavControllerbila diminta.
Observer menguji apakahMarsProperty—itdalam lambda—tidak null, dan jika ya, observer akan mendapatkan pengontrol navigasi dari fragmen denganfindNavController(). PanggildisplayPropertyDetailsComplete()untuk memberi tahu model tampilan agar meresetLiveDatake status null, sehingga Anda tidak akan secara tidak sengaja memicu navigasi lagi saat aplikasi kembali keOverviewFragment.
viewModel.navigateToSelectedProperty.observe(this, Observer {
if ( null != it ) {
this.findNavController().navigate(
OverviewFragmentDirections.actionShowDetail(it))
viewModel.displayPropertyDetailsComplete()
}
})- Buka
detail/DetailFragment.kt. Tambahkan baris ini tepat di bawah panggilan kesetLifecycleOwner()dalam metodeonCreateView(). Baris ini mendapatkan objekMarsPropertyyang dipilih dari Safe Args.
Perhatikan penggunaan operator pernyataan not-null Kotlin (!!). JikaselectedPropertytidak ada, sesuatu yang buruk telah terjadi dan Anda benar-benar ingin kode menampilkan pointer null. (Dalam kode produksi, Anda harus menangani error tersebut dengan cara tertentu.)
val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty- Tambahkan baris ini berikutnya, untuk mendapatkan
DetailViewModelFactorybaru. Anda akan menggunakanDetailViewModelFactoryuntuk mendapatkan instanceDetailViewModel. Aplikasi awal menyertakan implementasiDetailViewModelFactory, jadi yang perlu Anda lakukan di sini hanyalah menginisialisasinya.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)- Terakhir, tambahkan baris ini untuk mendapatkan
DetailViewModeldari pabrik dan menghubungkan semua bagian.
binding.viewModel = ViewModelProviders.of(
this, viewModelFactory).get(DetailViewModel::class.java)- Kompilasi dan jalankan aplikasi, lalu ketuk foto properti Mars mana pun. Fragmen detail akan muncul untuk detail properti tersebut. Ketuk tombol Kembali untuk kembali ke halaman ringkasan, dan perhatikan bahwa layar detail masih agak kosong. Anda akan menyelesaikan penambahan data properti ke halaman detail tersebut di tugas berikutnya.
Saat ini, halaman detail hanya menampilkan foto Mars yang sama yang biasa Anda lihat di halaman ringkasan. Class MarsProperty juga memiliki jenis properti (sewa atau beli) dan harga properti. Layar detail harus menyertakan kedua nilai ini, dan akan sangat membantu jika properti sewa menunjukkan bahwa harga adalah nilai per bulan. Anda menggunakan transformasi LiveData dalam model tampilan untuk menerapkan kedua hal tersebut.
- Buka
res/values/strings.xml. Kode awal menyertakan resource string, yang ditampilkan di bawah, untuk membantu Anda membuat string untuk tampilan detail. Untuk harga, Anda akan menggunakan resourcedisplay_price_monthly_rentalatau resourcedisplay_price, bergantung pada jenis properti.
<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>- Buka
detail/DetailViewModel.kt. Di bagian bawah class, tambahkan kode yang ditampilkan di bawah.
Imporandroidx.lifecycle.Transformationsjika diminta.
Transformasi ini menguji apakah properti yang dipilih adalah properti sewa, menggunakan pengujian yang sama dari tugas pertama. Jika properti adalah rental, transformasi memilih string yang sesuai dari resource dengan switchwhen {}Kotlin. Kedua string ini memerlukan angka di bagian akhir, jadi Anda menggabungkanproperty.pricesetelahnya.
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)
}- Impor class
Ryang dihasilkan untuk mendapatkan akses ke resource string dalam project.
import com.example.android.marsrealestate.R- Setelah transformasi
displayPropertyPrice, tambahkan kode yang ditunjukkan di bawah. Transformasi ini menggabungkan beberapa resource string, berdasarkan apakah jenis properti adalah rental.
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
}))
}- Buka
res/layout/fragment_detail.xml. Hanya ada satu hal lagi yang harus dilakukan, yaitu mengikat string baru (yang Anda buat dengan transformasiLiveData) ke tampilan detail. Untuk melakukannya, Anda menetapkan nilai kolom teks untuk teks jenis properti keviewModel.displayPropertyType, dan kolom teks untuk teks nilai harga keviewModel.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" />- Kompilasi dan jalankan aplikasi. Sekarang semua data properti muncul di halaman detail, dengan format yang bagus.

Project Android Studio: MarsRealEstateFinal
Ekspresi binding
- Gunakan ekspresi binding dalam file tata letak XML untuk melakukan operasi terprogram sederhana, seperti matematika atau pengujian bersyarat, pada data terikat.
- Untuk mereferensikan class di dalam file tata letak, gunakan tag
<import>di dalam tag<data>.
Opsi kueri layanan web
- Permintaan ke layanan web dapat mencakup parameter opsional.
- Untuk menentukan parameter kueri dalam permintaan, gunakan anotasi
@Querydi Retrofit.
Kursus Udacity:
Dokumentasi developer Android:
- Ringkasan ViewModel
- Ringkasan LiveData
- Adaptor binding
- Tata letak dan ekspresi binding
- Navigasi
- Memulai komponen Navigation
- Meneruskan data antar-tujuan (juga menjelaskan Safe Args)
- Class
Transformations - Class
ViewModelProvider - Class
ViewModelProvider.Factory
Lainnya:
Bagian ini mencantumkan kemungkinan tugas pekerjaan rumah untuk siswa yang mengerjakan codelab ini sebagai bagian dari kursus yang dipimpin oleh instruktur. Instruktur menentukan hal berikut:
- Memberikan pekerjaan rumah jika diperlukan.
- Memberi tahu siswa cara mengirimkan tugas pekerjaan rumah.
- Memberi nilai tugas pekerjaan rumah.
Instruktur bisa menggunakan saran ini sesuai kebutuhan, dan bebas menugaskan pekerjaan rumah lain yang dirasa cocok.
Jika Anda menyelesaikan codelab ini sendiri, gunakan tugas pekerjaan rumah ini untuk menguji pengetahuan Anda.
Jawab pertanyaan-pertanyaan berikut
Pertanyaan 1
Apa fungsi tag <import> dalam file tata letak XML?
▢ Sertakan satu file tata letak di file lainnya.
▢ Sematkan kode Kotlin dalam file tata letak.
▢ Sediakan akses ke properti yang terikat oleh data.
▢ Memungkinkan Anda mereferensikan class dan anggota class dalam ekspresi binding.
Pertanyaan 2
Bagaimana cara Anda menambahkan opsi kueri ke panggilan layanan web REST di Retrofit?
▢ Tambahkan kueri ke bagian akhir URL permintaan.
▢ Tambahkan parameter untuk kueri ke fungsi yang membuat permintaan, dan berikan anotasi parameter tersebut dengan @Query.
▢ Gunakan class Query untuk membuat permintaan.
▢ Gunakan metode addQuery() di builder Retrofit.
Mulai pelajaran berikutnya:
Untuk link ke codelab lain dalam kursus ini, lihat halaman landing codelab Dasar-Dasar Android Kotlin.