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
Pada codelab sebelumnya, Anda telah mempelajari cara mendapatkan data dari layanan web dan mengurai respons menjadi objek data. Dalam codelab ini, Anda menggunakan pengetahuan tersebut untuk memuat dan menampilkan foto dari URL web. Anda juga meninjau kembali cara membuat RecyclerView dan menggunakannya untuk menampilkan petak gambar pada halaman ringkasan.
Yang harus sudah Anda ketahui
- Cara membuat dan menggunakan fragmen.
- Cara menggunakan komponen arsitektur termasuk model tampilan, factory model tampilan, transformasi, dan
LiveData. - Cara mengambil JSON dari layanan web REST dan mengurai data tersebut ke dalam objek Kotlin menggunakan library Retrofit dan Moshi.
- Cara membuat tata letak petak dengan
RecyclerView. - Cara kerja
Adapter,ViewHolder, danDiffUtil.
Yang akan Anda pelajari
- Cara menggunakan library Glide untuk memuat dan menampilkan gambar dari URL web.
- Cara menggunakan
RecyclerViewdan adaptor petak untuk menampilkan petak gambar. - Cara menangani potensi error saat gambar didownload dan ditampilkan.
Yang akan Anda lakukan
- Memodifikasi aplikasi MarsRealEstate untuk mendapatkan URL gambar dari data properti Mars, dan menggunakan Glide untuk memuat dan menampilkan gambar tersebut.
- Menambahkan animasi pemuatan dan ikon error ke aplikasi.
- Gunakan
RecyclerViewuntuk menampilkan petak gambar properti Mars. - Tambahkan penanganan status dan error ke
RecyclerView.
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.

Versi aplikasi yang Anda buat dalam codelab ini akan terisi di halaman ringkasan, yang menampilkan petak gambar. Gambar adalah bagian dari data properti yang didapatkan aplikasi Anda dari layanan web properti Mars. Aplikasi Anda akan menggunakan library Glide untuk memuat dan menampilkan gambar, serta RecyclerView untuk membuat tata letak petak untuk gambar. Aplikasi Anda juga akan menangani error jaringan dengan baik.
Menampilkan foto dari URL web mungkin terdengar mudah, tetapi ada sedikit teknik untuk membuatnya berfungsi dengan baik. Gambar harus didownload, di-buffer, dan didekode-kan dari format terkompresi menjadi gambar yang dapat digunakan Android. Gambar harus di-cache ke cache dalam memori, cache berbasis penyimpanan, atau keduanya. Semua ini harus terjadi dalam thread latar belakang prioritas rendah sehingga UI tetap responsif. Selain itu, untuk performa jaringan dan CPU terbaik, Anda dapat mengambil dan mendekode lebih dari satu gambar sekaligus. Mempelajari cara memuat gambar secara efektif dari jaringan bisa menjadi codelab tersendiri.
Untungnya, Anda dapat menggunakan library yang dikembangkan komunitas yang disebut Glide untuk mendownload, melakukan buffering, mendekode, dan meng-cache gambar Anda. Glide membuat pekerjaan Anda jauh lebih mudah daripada jika Anda harus melakukan semua ini dari awal.
Pada dasarnya, Glide memerlukan dua hal:
- URL gambar yang ingin Anda muat dan tampilkan.
- Objek
ImageViewuntuk menampilkan gambar tersebut.
Dalam tugas ini, Anda akan mempelajari cara menggunakan Glide untuk menampilkan satu gambar dari layanan web real estate. Anda menampilkan gambar yang mewakili properti Mars pertama dalam daftar properti yang ditampilkan oleh layanan web. Berikut adalah screenshot sebelum dan sesudah:


Langkah 1: Tambahkan dependensi Glide
- Buka aplikasi MarsRealEstate dari codelab terakhir. (Anda dapat mendownload MarsRealEstateNetwork di sini jika Anda tidak memiliki aplikasi tersebut.)
- Jalankan aplikasi untuk melihat fungsinya. (Menampilkan detail teks properti yang secara hipotetis tersedia di Mars.)
- Buka build.gradle (Module: app).
- Di bagian
dependencies, tambahkan baris ini untuk library Glide:
implementation "com.github.bumptech.glide:glide:$version_glide"
Perhatikan bahwa nomor versi sudah ditentukan secara terpisah dalam file Gradle project.
- Klik Sync Now untuk membuat ulang project dengan dependensi baru.
Langkah 2: Perbarui model tampilan
Selanjutnya, Anda memperbarui class OverviewViewModel untuk menyertakan data live untuk satu properti Mars.
- Buka
overview/OverviewViewModel.kt. Tepat di bawahLiveDatauntuk_response, tambahkan data live internal (dapat berubah) dan eksternal (tidak dapat berubah) untuk satu objekMarsProperty.
Impor classMarsProperty(com.example.android.marsrealestate.network.MarsProperty) saat diminta.
private val _property = MutableLiveData<MarsProperty>()
val property: LiveData<MarsProperty>
get() = _property- Pada metode
getMarsRealEstateProperties(), temukan baris di dalam bloktry/catch {}yang menyetel_response.valueke jumlah properti. Tambahkan pengujian yang ditunjukkan di bawah. Jika objekMarsPropertytersedia, pengujian ini akan menetapkan nilaiLiveData_propertyke properti pertama dilistResult.
if (listResult.size > 0) {
_property.value = listResult[0]
}Blok lengkap try/catch {} sekarang terlihat seperti ini:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
if (listResult.size > 0) {
_property.value = listResult[0]
}
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}- Buka file
res/layout/fragment_overview.xml. Dalam elemen<TextView>, ubahandroid:textuntuk terikat ke komponenimgSrcUrldaripropertyLiveData:
android:text="@{viewModel.property.imgSrcUrl}"- Jalankan aplikasi.
TextViewhanya menampilkan URL gambar di properti Mars pertama. Semua yang telah Anda lakukan sejauh ini adalah menyiapkan model tampilan dan data live untuk URL tersebut.

Langkah 3: Buat adaptor pengikatan dan panggil Glide
Sekarang Anda memiliki URL gambar untuk ditampilkan, dan saatnya mulai menggunakan Glide untuk memuat gambar tersebut. Pada langkah ini, Anda menggunakan adaptor binding untuk mengambil URL dari atribut XML yang terkait dengan ImageView, dan Anda menggunakan Glide untuk memuat gambar. Adaptor binding adalah metode ekstensi yang berada di antara tampilan dan data terikat untuk memberikan perilaku kustom saat data berubah. Dalam hal ini, perilaku kustomnya adalah memanggil Glide untuk memuat gambar dari URL ke dalam ImageView.
- Buka
BindingAdapters.kt. File ini akan menyimpan adaptor binding yang Anda gunakan di seluruh aplikasi. - Buat fungsi
bindImage()yang menggunakan parameterImageViewdanString. Anotasikan fungsi dengan@BindingAdapter. Anotasi@BindingAdaptermemberi tahu data binding bahwa Anda ingin adaptor binding ini dieksekusi saat item XML memiliki atributimageUrl.
Imporandroidx.databinding.BindingAdapterdanandroid.widget.ImageViewbila diminta.
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
}- Di dalam fungsi
bindImage(), tambahkan bloklet {}untuk argumenimgUrl:
imgUrl?.let {
}- Di dalam blok
let {}, tambahkan baris yang ditunjukkan di bawah untuk mengonversi string URL (dari XML) menjadi objekUri. Imporandroidx.core.net.toUrisaat diminta.
Anda ingin objekUriakhir menggunakan skema HTTPS, karena server tempat Anda menarik gambar memerlukan skema tersebut. Untuk menggunakan skema HTTPS, tambahkanbuildUpon.scheme("https")ke buildertoUri. MetodetoUri()adalah fungsi ekstensi Kotlin dari library inti Android KTX, sehingga terlihat seperti bagian dari classString.
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()- Masih di dalam
let {}, panggilGlide.with()untuk memuat gambar dari objekUrikeImageView. Imporcom.bumptech.glide.Glidebila diminta.
Glide.with(imgView.context)
.load(imgUri)
.into(imgView)Langkah 4: Perbarui tata letak dan fragmen
Meskipun Glide telah memuat gambar, belum ada yang dapat dilihat. Langkah selanjutnya adalah memperbarui tata letak dan fragmen dengan ImageView untuk menampilkan gambar.
- Buka
res/layout/gridview_item.xml. Ini adalah file resource tata letak yang akan Anda gunakan untuk setiap item diRecyclerViewnanti dalam codelab. Anda menggunakannya di sini untuk sementara guna menampilkan satu gambar saja. - Di atas elemen
<ImageView>, tambahkan elemen<data>untuk data binding, dan binding ke classOverviewViewModel:
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.overview.OverviewViewModel" />
</data>- Tambahkan atribut
app:imageUrlke elemenImageViewuntuk menggunakan adaptor binding pemuatan gambar baru:
app:imageUrl="@{viewModel.property.imgSrcUrl}"- Buka
overview/OverviewFragment.kt. Dalam metodeonCreateView(), jadikan baris sebagai komentar, yaitu baris yang meng-inflate classFragmentOverviewBindingdan menetapkannya ke variabel binding. Ini hanya sementara; Anda akan kembali ke sana nanti.
//val binding = FragmentOverviewBinding.inflate(inflater)- Tambahkan baris untuk meng-inflate class
GridViewItemBinding. Imporcom.example.android.marsrealestate. databinding.GridViewItemBindingbila diminta.
val binding = GridViewItemBinding.inflate(inflater)- Jalankan aplikasi. Sekarang Anda akan melihat foto gambar dari
MarsPropertypertama dalam daftar hasil.
Langkah 5: Tambahkan gambar pemuatan dan error sederhana
Glide dapat meningkatkan kualitas pengalaman pengguna dengan menampilkan gambar placeholder saat memuat gambar dan gambar error jika pemuatan gagal, misalnya jika gambar hilang atau rusak. Pada langkah ini, Anda akan menambahkan fungsi tersebut ke adaptor binding dan ke tata letak.
- Buka
res/drawable/ic_broken_image.xml, lalu klik tab Preview di sebelah kanan. Untuk gambar error, Anda menggunakan ikon gambar rusak yang tersedia di library ikon bawaan. Vektor drawable ini menggunakan atributandroid:tintuntuk mewarnai ikon menjadi abu-abu.

- Buka
res/drawable/loading_animation.xml. Drawable ini adalah animasi yang ditentukan dengan tag<animate-rotate>. Animasi memutar drawable gambar,loading_img.xml, mengitari titik tengah. (Anda tidak melihat animasinya di pratinjau.)

- Kembali ke file
BindingAdapters.kt. Pada metodebindImage(), update panggilan keGlide.with()untuk memanggil fungsiapply()di antaraload()daninto(). Imporcom.bumptech.glide.request.RequestOptionssaat diminta.
Kode ini menetapkan gambar pemuatan placeholder yang akan digunakan saat memuat (drawableloading_animation). Kode ini juga menetapkan gambar yang akan digunakan jika pemuatan gambar gagal (drawablebroken_image). MetodebindImage()lengkap kini terlihat seperti ini:
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
imgUrl?.let {
val imgUri =
imgUrl.toUri().buildUpon().scheme("https").build()
Glide.with(imgView.context)
.load(imgUri)
.apply(RequestOptions()
.placeholder(R.drawable.loading_animation)
.error(R.drawable.ic_broken_image))
.into(imgView)
}
}
- Jalankan aplikasi. Bergantung pada kecepatan koneksi jaringan, Anda mungkin melihat gambar pemuatan secara cepat saat Glide mendownload dan menampilkan gambar properti. Namun, Anda tidak akan melihat ikon gambar yang rusak meskipun jaringan dinonaktifkan—Anda akan memperbaiki error di bagian terakhir codelab.
Aplikasi Anda sekarang memuat informasi properti dari internet. Dengan menggunakan data dari item daftar MarsProperty pertama, Anda telah membuat properti LiveData di model tampilan, dan telah menggunakan URL gambar dari data properti tersebut untuk mengisi ImageView. Namun, tujuannya adalah agar aplikasi Anda menampilkan petak gambar, sehingga Anda ingin menggunakan RecyclerView dengan GridLayoutManager.
Langkah 1: Perbarui model tampilan
Saat ini, model tampilan memiliki _property LiveData yang menyimpan satu objek MarsProperty—objek pertama dalam daftar respons dari layanan web. Pada langkah ini, Anda mengubah LiveData tersebut untuk menyimpan seluruh daftar objek MarsProperty.
- Buka
overview/OverviewViewModel.kt. - Ubah variabel
_propertypribadi menjadi_properties. Ubah jenisnya menjadi daftar objekMarsProperty.
private val _properties = MutableLiveData<List<MarsProperty>>()- Ganti data live
propertyeksternal denganproperties. Tambahkan daftar ke jenisLiveDatadi sini juga:
val properties: LiveData<List<MarsProperty>>
get() = _properties- Scroll ke bawah, ke metode
getMarsRealEstateProperties(). Di dalam bloktry {}, ganti seluruh pengujian yang Anda tambahkan pada tugas sebelumnya dengan baris yang ditampilkan di bawah. Karena variabellistResultmenyimpan daftar objekMarsProperty, Anda cukup menetapkannya ke_properties.value, bukan menguji respons yang berhasil.
_properties.value = listResultSeluruh blok try/catch sekarang terlihat seperti ini:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
_properties.value = listResult
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}Langkah 2: Perbarui tata letak dan fragmen
Langkah berikutnya adalah mengubah tata letak dan fragmen aplikasi untuk menggunakan tampilan recycler dan tata letak petak, bukan satu tampilan gambar.
- Buka
res/layout/gridview_item.xml. Ubah data binding dariOverviewViewModelmenjadiMarsProperty, lalu ganti nama variabel menjadi"property".
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" />- Di
<ImageView>, ubah atributapp:imageUrluntuk merujuk ke URL gambar di objekMarsProperty:
app:imageUrl="@{property.imgSrcUrl}"- Buka
overview/OverviewFragment.kt. DionCreateview(), hapus tanda komentar pada baris yang meng-inflateFragmentOverviewBinding. Hapus atau jadikan baris yang meng-inflateGridViewBindingsebagai komentar. Perubahan ini mengurungkan perubahan sementara yang Anda buat di tugas terakhir.
val binding = FragmentOverviewBinding.inflate(inflater)
// val binding = GridViewItemBinding.inflate(inflater)- Buka
res/layout/fragment_overview.xml. Hapus seluruh elemen<TextView>. - Sebagai gantinya, tambahkan elemen
<RecyclerView>ini, yang menggunakanGridLayoutManagerdan tata letakgrid_view_itemuntuk satu item:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/photos_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="6dp"
android:clipToPadding="false"
app:layoutManager=
"androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="2"
tools:itemCount="16"
tools:listitem="@layout/grid_view_item" />Langkah 3: Tambahkan adaptor petak foto
Sekarang tata letak fragment_overview memiliki RecyclerView, sedangkan tata letak grid_view_item memiliki satu ImageView. Pada langkah ini, Anda akan mengikat data ke RecyclerView melalui adaptor RecyclerView.
- Buka
overview/PhotoGridAdapter.kt. - Buat class
PhotoGridAdapter, dengan parameter konstruktor yang ditampilkan di bawah ini. ClassPhotoGridAdaptermemperluasListAdapter, yang konstruktornya memerlukan jenis item daftar, holder tampilan, dan implementasiDiffUtil.ItemCallback.
Impor classandroidx.recyclerview.widget.ListAdapterdancom.example.android.marsrealestate.network.MarsPropertybila diminta. Pada langkah-langkah berikut, Anda akan menerapkan bagian lain yang hilang dari konstruktor ini, yang menghasilkan error.
class PhotoGridAdapter : ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
}- Klik di mana saja dalam class
PhotoGridAdapter, lalu tekanControl+iuntuk menerapkan metodeListAdapter, yaituonCreateViewHolder()danonBindViewHolder().
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoGridAdapter.MarsPropertyViewHolder {
TODO("not implemented")
}
override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
TODO("not implemented")
}- Di akhir definisi class
PhotoGridAdapter, setelah metode yang baru saja Anda tambahkan, tambahkan definisi objek pendamping untukDiffCallback, seperti yang ditunjukkan di bawah ini.
Imporandroidx.recyclerview.widget.DiffUtilbila diminta.
ObjekDiffCallbackmemperluasDiffUtil.ItemCallbackdengan jenis objek yang ingin Anda bandingkan—MarsProperty.
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}- Tekan
Control+iuntuk mengimplementasikan metode pembanding untuk objek ini, yaituareItemsTheSame()danareContentsTheSame().
override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented")
}
override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented") }- Untuk metode
areItemsTheSame(), hapus TODO. Gunakan operator persamaan referensial Kotlin (===), yang menampilkantruejika referensi objek untukoldItemdannewItemsama.
override fun areItemsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem === newItem
}- Untuk
areContentsTheSame(), gunakan operator kesetaraan standar hanya pada IDoldItemdannewItem.
override fun areContentsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem.id == newItem.id
}- Masih di dalam class
PhotoGridAdapter, di bawah objek pendamping, tambahkan definisi class internal untukMarsPropertyViewHolder, yang memperluasRecyclerView.ViewHolder.
Imporandroidx.recyclerview.widget.RecyclerViewdancom.example.android.marsrealestate.databinding.GridViewItemBindingjika diminta.
Anda memerlukan variabelGridViewItemBindinguntuk mengikatMarsPropertyke tata letak, jadi teruskan variabel tersebut ke dalamMarsPropertyViewHolder. Karena classViewHolderdasar memerlukan tampilan dalam konstruktornya, Anda meneruskannya dengan tampilan root binding.
class MarsPropertyViewHolder(private var binding:
GridViewItemBinding):
RecyclerView.ViewHolder(binding.root) {
}- Di
MarsPropertyViewHolder, buat metodebind()yang menggunakan objekMarsPropertysebagai argumen dan menyetelbinding.propertyke objek tersebut. PanggilexecutePendingBindings()setelah menetapkan properti, yang menyebabkan update segera dijalankan.
fun bind(marsProperty: MarsProperty) {
binding.property = marsProperty
binding.executePendingBindings()
}- Di
onCreateViewHolder(), hapus TODO dan tambahkan baris yang ditunjukkan di bawah. Imporandroid.view.LayoutInflaterbila diminta.
MetodeonCreateViewHolder()perlu menampilkanMarsPropertyViewHolderbaru, yang dibuat dengan meng-inflateGridViewItemBindingdan menggunakanLayoutInflaterdari konteksViewGroupinduk.
return MarsPropertyViewHolder(GridViewItemBinding.inflate(
LayoutInflater.from(parent.context)))- Dalam metode
onBindViewHolder(), hapus TODO dan tambahkan baris yang ditampilkan di bawah ini. Di sini, panggilgetItem()untuk mendapatkan objekMarsPropertyyang terkait dengan posisiRecyclerViewsaat ini, lalu teruskan properti tersebut ke metodebind()diMarsPropertyViewHolder.
val marsProperty = getItem(position)
holder.bind(marsProperty)Langkah 4: Tambahkan adaptor binding dan sambungkan bagian-bagiannya
Terakhir, gunakan BindingAdapter untuk menginisialisasi PhotoGridAdapter dengan daftar objek MarsProperty. Menggunakan BindingAdapter untuk menyetel data RecyclerView menyebabkan data binding secara otomatis mengamati LiveData untuk daftar objek MarsProperty. Kemudian, adaptor binding dipanggil secara otomatis saat daftar MarsProperty berubah.
- Buka
BindingAdapters.kt. - Di akhir file, tambahkan metode
bindRecyclerView()yang menggunakanRecyclerViewdan daftar objekMarsPropertysebagai argumen. Anotasikan metode tersebut dengan@BindingAdapter.
Imporandroidx.recyclerview.widget.RecyclerViewdancom.example.android.marsrealestate.network.MarsPropertybila diminta.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView,
data: List<MarsProperty>?) {
}- Di dalam fungsi
bindRecyclerView(), transmisirecyclerView.adapterkePhotoGridAdapter, dan panggiladapter.submitList()dengan data. Ini akan memberi tahuRecyclerViewsaat daftar baru tersedia.
Impor com.example.android.marsrealestate.overview.PhotoGridAdapter bila diminta.
val adapter = recyclerView.adapter as PhotoGridAdapter
adapter.submitList(data)- Buka
res/layout/fragment_overview.xml. Tambahkan atributapp:listDatake elemenRecyclerViewdan tetapkan keviewmodel.propertiesmenggunakan data binding.
app:listData="@{viewModel.properties}"- Buka
overview/OverviewFragment.kt. DionCreateView(), tepat sebelum panggilan kesetHasOptionsMenu(), inisialisasi adaptorRecyclerViewdibinding.photosGridmenjadi objekPhotoGridAdapterbaru.
binding.photosGrid.adapter = PhotoGridAdapter()- Jalankan aplikasi. Anda akan melihat petak gambar
MarsProperty. Saat Anda men-scroll untuk melihat gambar baru, aplikasi akan menampilkan ikon progres pemuatan sebelum menampilkan gambar itu sendiri. Jika Anda mengaktifkan mode pesawat, gambar yang belum dimuat akan muncul sebagai ikon gambar yang rusak.

Aplikasi MarsRealEstate menampilkan ikon gambar rusak saat gambar tidak dapat diambil. Namun saat tidak ada jaringan, aplikasi akan menampilkan layar kosong.

Ini bukan pengalaman pengguna yang baik. Dalam tugas ini, Anda akan menambahkan penanganan error dasar, untuk memberikan ide yang lebih baik kepada pengguna tentang apa yang terjadi. Jika internet tidak tersedia, aplikasi akan menampilkan ikon error koneksi. Saat aplikasi mengambil daftar MarsProperty, aplikasi akan menampilkan animasi pemuatan.
Langkah 1: Menambahkan status ke model tampilan
Untuk memulai, Anda membuat LiveData di model tampilan untuk mewakili status permintaan web. Ada tiga status untuk dipertimbangkan—memuat, berhasil, dan kegagalan. Status pemuatan terjadi saat Anda menunggu data dalam panggilan ke await().
- Buka
overview/OverviewViewModel.kt. Di bagian atas file (setelah impor, sebelum definisi class), tambahkanenumuntuk mewakili semua status yang tersedia:
enum class MarsApiStatus { LOADING, ERROR, DONE }- Ganti nama definisi data live
_responseinternal dan eksternal di seluruh classOverviewViewModelmenjadi_status. Karena Anda menambahkan dukungan untuk_propertiesLiveDatasebelumnya dalam codelab ini, respons layanan web lengkap tidak digunakan. Anda memerlukanLiveDatadi sini untuk melacak status saat ini, jadi Anda cukup mengganti nama variabel yang ada.
Selain itu, ubah jenis dari String menjadi MarsApiStatus.
private val _status = MutableLiveData<MarsApiStatus>()
val status: LiveData<MarsApiStatus>
get() = _status- Scroll ke bawah, ke metode
getMarsRealEstateProperties(), lalu perbarui_responsemenjadi_statusdi sini juga. Ubah string"Success"menjadi statusMarsApiStatus.DONE, dan string"Failure"menjadiMarsApiStatus.ERROR. - Tambahkan status
MarsApiStatus.LOADINGke bagian atas bloktry {}, sebelum panggilan keawait(). Ini adalah status awal saat coroutine berjalan dan Anda sedang menunggu data. Bloktry/catch {}lengkap sekarang terlihat seperti ini:
try {
_status.value = MarsApiStatus.LOADING
var listResult = getPropertiesDeferred.await()
_status.value = MarsApiStatus.DONE
_properties.value = listResult
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
}- Setelah status error di blok
catch {}, setel_propertiesLiveDatake daftar kosong. Tindakan ini akan menghapusRecyclerView.
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
_properties.value = ArrayList()
}Langkah 2: Tambahkan adaptor binding untuk status ImageView
Sekarang Anda memiliki status di model tampilan, tetapi hanya berupa kumpulan status. Bagaimana cara menampilkannya di aplikasi itu sendiri? Pada langkah ini, Anda menggunakan ImageView, yang terhubung ke data binding, untuk menampilkan ikon untuk status pemuatan dan error. Saat aplikasi berada dalam status pemuatan atau status error, ImageView akan terlihat. Saat aplikasi selesai dimuat, ImageView seharusnya tidak terlihat.
- Buka
BindingAdapters.kt. Tambahkan adaptor binding baru bernamabindStatus()yang menggunakan nilaiImageViewdanMarsApiStatussebagai argumen. Imporcom.example.android.marsrealestate.overview.MarsApiStatusbila diminta.
@BindingAdapter("marsApiStatus")
fun bindStatus(statusImageView: ImageView,
status: MarsApiStatus?) {
}- Tambahkan
when {}di dalam metodebindStatus()untuk beralih antar-status.
when (status) {
}- Di dalam
when {}, tambahkan kasus untuk status pemuatan (MarsApiStatus.LOADING). Untuk status ini, setelImageViewmenjadi terlihat, dan tetapkan animasi pemuatan. Ini adalah drawable animasi yang sama dengan yang digunakan untuk Glide dalam tugas sebelumnya. Imporandroid.view.Viewbila diminta.
when (status) {
MarsApiStatus.LOADING -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.loading_animation)
}
}- Tambahkan kasus untuk status error, yaitu
MarsApiStatus.ERROR. Demikian pula dengan apa yang Anda lakukan untuk statusLOADING, setel statusImageViewmenjadi terlihat dan gunakan kembali drawable koneksi-error.
MarsApiStatus.ERROR -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.ic_connection_error)
}- Tambahkan kasus untuk status selesai, yaitu
MarsApiStatus.DONE. Di sini Anda memiliki respons yang berhasil, jadi nonaktifkan visibilitas statusImageViewuntuk menyembunyikannya.
MarsApiStatus.DONE -> {
statusImageView.visibility = View.GONE
}Langkah 3: Tambahkan status ImageView ke tata letak
- Buka
res/layout/fragment_overview.xml. Di bawah elemenRecyclerView, di dalamConstraintLayout, tambahkanImageViewyang ditunjukkan di bawah.ImageViewini memiliki batasan yang sama denganRecyclerView. Namun, lebar dan tinggi menggunakanwrap_contentuntuk menengahkan gambar, bukan melebarkan gambar untuk memenuhi tampilan. Perhatikan juga atributapp:marsApiStatus, yang membuat tampilan memanggilBindingAdapterAnda saat properti status di model tampilan berubah.
<ImageView
android:id="@+id/status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marsApiStatus="@{viewModel.status}" />- Aktifkan mode pesawat di emulator atau perangkat Anda untuk menyimulasikan koneksi jaringan yang tidak ada. Kompilasi dan jalankan aplikasi, dan perhatikan bahwa gambar error muncul:

- Ketuk tombol Kembali untuk menutup aplikasi dan nonaktifkan mode pesawat. Gunakan layar terbaru untuk menampilkan aplikasi. Bergantung pada kecepatan koneksi jaringan, Anda mungkin melihat indikator lingkaran berputar yang sangat singkat saat aplikasi menanyakan layanan web sebelum gambar mulai dimuat.
Project Android Studio: MarsRealEstateGrid
- Untuk menyederhanakan proses pengelolaan gambar, gunakan library Glide untuk mendownload, melakukan buffering, mendekode, dan meng-cache gambar di aplikasi Anda.
- Glide memerlukan dua hal untuk memuat gambar dari internet: URL gambar, dan objek
ImageViewuntuk menempatkan gambar. Untuk menentukan opsi ini, gunakan metodeload()daninto()dengan Glide. - Adaptor Binding adalah metode ekstensi yang berada di antara tampilan dan data terikat tampilan. Adaptor binding menyediakan perilaku kustom saat data berubah, misalnya, untuk memanggil Glide guna memuat gambar dari URL ke dalam
ImageView. - Adaptor binding adalah metode ekstensi yang dianotasi dengan anotasi
@BindingAdapter. - Untuk menambahkan opsi ke permintaan Glide, gunakan metode
apply(). Misalnya, gunakanapply()denganplaceholder()untuk menentukan drawable pemuatan, dan gunakanapply()denganerror()untuk menentukan drawable error. - Untuk menghasilkan petak gambar, gunakan
RecyclerViewdenganGridLayoutManager. - Untuk memperbarui daftar properti saat berubah, gunakan adaptor binding antara
RecyclerViewdan tata letak.
Kursus Udacity:
Dokumentasi developer Android:
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
Metode Glide mana yang Anda gunakan untuk menunjukkan ImageView yang akan berisi gambar yang dimuat?
▢ into()
▢ with()
▢ imageview()
▢ apply()
Pertanyaan 2
Bagaimana cara Anda menentukan gambar placeholder untuk ditampilkan saat Glide memuat?
▢ Gunakan metode into() dengan drawable.
▢ Gunakan RequestOptions() dan panggil metode placeholder() dengan drawable.
▢ Tetapkan properti Glide.placeholder ke drawable.
▢ Gunakan RequestOptions() dan panggil metode loadingImage() dengan drawable.
Pertanyaan 3
Bagaimana cara Anda menunjukkan bahwa suatu metode merupakan adaptor binding?
▢ Panggil metode setBindingAdapter() pada LiveData.
▢ Masukkan metode ke dalam file Kotlin bernama BindingAdapters.kt.
▢ Gunakan atribut android:adapter dalam tata letak XML.
▢ Anotasikan metode dengan @BindingAdapter.
Mulai pelajaran berikutnya:
Untuk link ke codelab lain dalam kursus ini, lihat halaman landing codelab Dasar-Dasar Android Kotlin.