Memuat dan menampilkan gambar dari internet

1. Sebelum memulai

Pengantar

Dalam codelab sebelumnya, Anda telah mempelajari cara mendapatkan data dari layanan web menggunakan pola repositori dan mengurai respons menjadi objek Kotlin. Dalam codelab ini, Anda menggunakan pengetahuan tersebut untuk memuat dan menampilkan foto dari URL web. Anda juga meninjau kembali cara membuat LazyVerticalGrid dan menggunakannya untuk menampilkan petak gambar pada halaman ringkasan.

Prasyarat

  • Mengetahui cara mengambil JSON dari layanan web REST dan penguraian data tersebut menjadi objek Kotlin menggunakan library Retrofit dan Gson
  • Mengetahui layanan web REST
  • Memahami komponen arsitektur Android, seperti lapisan data dan repositori
  • Mengetahui injeksi dependensi
  • Mengetahui ViewModel dan ViewModelProvider.Factory
  • Mengetahui implementasi coroutine untuk aplikasi
  • Mengetahui pola repositori

Yang akan Anda pelajari

  • Cara menggunakan library Coil untuk memuat dan menampilkan gambar dari URL web.
  • Cara menggunakan LazyVerticalGrid untuk menampilkan petak gambar.
  • Cara menangani potensi error saat gambar didownload dan ditampilkan.

Yang akan Anda build

  • Memodifikasi aplikasi Mars Photos untuk mendapatkan URL gambar dari data Mars, dan menggunakan Coil untuk memuat dan menampilkan gambar itu.
  • Menambahkan animasi pemuatan dan ikon error ke aplikasi.
  • Menambahkan penanganan status dan error ke aplikasi.

Yang Anda butuhkan

  • Komputer dengan browser web modern, seperti Chrome versi terbaru
  • Kode awal untuk aplikasi Mars Photosdengan layanan web REST

2. Ringkasan aplikasi

Dalam codelab ini, Anda akan kembali menggunakan aplikasi Mars Photos dari codelab sebelumnya. Aplikasi Mars Photos terhubung ke layanan web untuk mengambil dan menampilkan jumlah objek Kotlin yang diambil menggunakan Gson. Objek Kotlin ini berisi URL foto kehidupan nyata dari permukaan Mars yang diambil dari Wahana Penjelajah Mars (Mars Rover) NASA.

a59e55909b6e9213.png

Versi aplikasi yang Anda bangun di codelab ini menampilkan foto Mars dalam petak gambar. Gambar tersebut merupakan bagian dari data yang diambil aplikasi Anda dari layanan web. Aplikasi Anda akan menggunakan library Coil untuk memuat dan menampilkan gambar, serta LazyVerticalGrid untuk membuat tata letak petak untuk gambar. Aplikasi Anda juga akan menangani error jaringan secara halus dengan menampilkan pesan error.

68f4ff12cc1e2d81.png

Mendapatkan kode awal

Untuk memulai, download kode awal:

Atau, Anda dapat membuat clone repositori GitHub untuk kode tersebut:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-mars-photos.git
$ cd basic-android-kotlin-compose-training-mars-photos
$ git checkout coil-starter

Anda dapat menjelajahi kode di repositori GitHub Mars Photos.

3. Menampilkan gambar yang didownload

Menampilkan foto dari URL web mungkin terdengar mudah, tetapi ada sedikit teknik untuk membuatnya berfungsi dengan baik. Gambar harus didownload, disimpan secara internal (di-cache), dan didekode-kan dari format terkompresi menjadi gambar yang dapat digunakan Android. Anda dapat meng-cache gambar ke cache dalam memori, cache berbasis penyimpanan, atau keduanya. Semua proses ini harus berlangsung di thread latar belakang prioritas rendah agar UI tetap responsif. Selain itu, untuk performa jaringan dan CPU terbaik, Anda dapat mengambil dan mendekode lebih dari satu gambar sekaligus.

Untungnya, Anda dapat menggunakan library yang dikembangkan komunitas yang disebut Coil untuk mendownload, melakukan buffering, mendekode, dan meng-cache gambar Anda. Tanpa menggunakan Coil, Anda akan memiliki lebih banyak pekerjaan yang harus dilakukan.

Coil pada dasarnya memerlukan dua hal:

  • URL gambar yang ingin Anda muat dan tampilkan.
  • Composable AsyncImage untuk benar-benar menampilkan gambar tersebut.

Dalam tugas ini, Anda akan mempelajari cara menggunakan Coil untuk menampilkan satu gambar dari layanan web Mars. Anda menampilkan gambar foto Mars pertama dalam daftar foto yang ditampilkan oleh layanan web. Gambar berikut menampilkan screenshot sebelum dan sesudah:

a59e55909b6e9213.png 1b670f284109bbf5.png

Menambahkan dependensi Coil

  1. Buka aplikasi solusi Mars Photos dari codelab Menambahkan repositori dan DI Manual.
  2. Jalankan aplikasi untuk mengonfirmasi bahwa aplikasi menampilkan jumlah foto Mars yang diambil.
  3. Buka build.gradle.kts (Module :app).
  4. Di bagian dependencies, tambahkan baris ini untuk library Coil:
// Coil
implementation("io.coil-kt:coil-compose:2.4.0")

Periksa dan update versi terbaru library dari halaman dokumentasi Coil.

  1. Klik Sync Now untuk membuat ulang project dengan dependensi baru.

Menampilkan URL Gambar

Pada langkah ini, Anda akan mengambil dan menampilkan URL foto pertama Mars.

  1. Pada ui/screens/MarsViewModel.kt, di dalam metode getMarsPhotos(), di dalam blok try, cari baris yang menetapkan data yang diambil dari layanan web menjadi listResult.
// No need to copy, code is already present
try {
   val listResult = marsPhotosRepository.getMarsPhotos()
   //...
}
  1. Perbarui baris ini dengan mengubah listResult menjadi result dan menetapkan foto pertama Mars yang diambil ke variabel baru result. Tetapkan objek foto pertama di indeks 0.
try {
   val result = marsPhotosRepository.getMarsPhotos()[0]
   //...
}
  1. Pada baris berikutnya, perbarui parameter yang diteruskan ke panggilan fungsi MarsUiState.Success() ke string dalam kode berikut. Gunakan data dari properti baru, bukan listResult. Tampilkan URL gambar pertama dari foto result.
try {
   ...
   MarsUiState.Success("First Mars image URL: ${result.imgSrc}")
}

Blok try lengkap kini terlihat seperti kode berikut:

marsUiState = try {
   val result = marsPhotosRepository.getMarsPhotos()[0]
   MarsUiState.Success(
       "   First Mars image URL : ${result.imgSrc}"
   )
}
  1. Jalankan aplikasi. Composable Text kini menampilkan URL foto pertama Mars. Bagian berikutnya menjelaskan cara membuat aplikasi menampilkan gambar di URL ini.

b5daaa892fe8dad7.png

Menambahkan composable AsyncImage

Pada langkah ini, Anda akan menambahkan fungsi composable AsyncImage untuk memuat dan menampilkan satu foto Mars. AsyncImage adalah composable yang menjalankan permintaan gambar secara asinkron lalu merender hasilnya.

// Example code, no need to copy over
AsyncImage(
    model = "https://android.com/sample_image.jpg",
    contentDescription = null
)

Argumen model dapat berupa nilai ImageRequest.data atau ImageRequest. Pada contoh sebelumnya, Anda menetapkan nilai ImageRequest.data—yaitu, URL gambar, yaitu "https://android.com/sample_image.jpg". Kode contoh berikut menunjukkan cara menetapkan ImageRequest ke model.

// Example code, no need to copy over

AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data("https://example.com/image.jpg")
        .crossfade(true)
        .build(),
    placeholder = painterResource(R.drawable.placeholder),
    contentDescription = stringResource(R.string.description),
    contentScale = ContentScale.Crop,
    modifier = Modifier.clip(CircleShape)
)

AsyncImage mendukung argumen yang sama seperti composable Image standar. Selain itu, composable ini mendukung penyetelan painter placeholder/error/fallback dan callback onLoading/onSuccess/onError. Kode contoh sebelumnya memuat gambar dengan pemangkasan lingkaran dan crossfade, dan menetapkan placeholder.

contentDescription menetapkan teks yang digunakan oleh layanan aksesibilitas untuk mendeskripsikan item yang diwakili oleh gambar ini.

Tambahkan composable AsyncImage ke kode Anda untuk menampilkan foto pertama Mars yang diambil.

  1. Di ui/screens/HomeScreen.kt, tambahkan fungsi composable baru yang disebut MarsPhotoCard(), yang menggunakan MarsPhoto dan Modifier.
@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
}
  1. Di dalam fungsi composable MarsPhotoCard(), tambahkan fungsi AsyncImage() sebagai berikut:
import coil.compose.AsyncImage
import coil.request.ImageRequest
import androidx.compose.ui.platform.LocalContext

@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
    AsyncImage(
        model = ImageRequest.Builder(context = LocalContext.current)
            .data(photo.imgSrc)
            .build(),
        contentDescription = stringResource(R.string.mars_photo),
        modifier = Modifier.fillMaxWidth()
    )
}

Pada kode sebelumnya, Anda mem-build ImageRequest menggunakan URL gambar (photo.imgSrc) dan meneruskannya ke argumen model. Anda menggunakan contentDescription untuk menetapkan teks bagi pembaca aksesibilitas.

  1. Tambahkan crossfade(true) ke ImageRequest untuk mengaktifkan animasi crossfade saat permintaan berhasil diselesaikan.
@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
    AsyncImage(
        model = ImageRequest.Builder(context = LocalContext.current)
            .data(photo.imgSrc)
            .crossfade(true)
            .build(),
        contentDescription = stringResource(R.string.mars_photo),
        modifier = Modifier.fillMaxWidth()
    )
}
  1. Perbarui composable HomeScreen untuk menampilkan composable MarsPhotoCard, bukan composable ResultScreen, saat permintaan berhasil diselesaikan. Anda dapat memperbaiki error ketidakcocokan jenis pada langkah berikutnya.
@Composable
fun HomeScreen(
    marsUiState: MarsUiState,
    modifier: Modifier = Modifier
) {
    when (marsUiState) {
        is MarsUiState.Loading -> LoadingScreen(modifier = modifier.fillMaxSize())
        is MarsUiState.Success -> MarsPhotoCard(photo = marsUiState.photos, modifier = modifier.fillMaxSize())
        else -> ErrorScreen(modifier = modifier.fillMaxSize())
    }
}
  1. Dalam file MarsViewModel.kt, perbarui antarmuka MarsUiState agar dapat menerima objek MarsPhoto, bukan String.
sealed interface MarsUiState {
    data class Success(val photos: MarsPhoto) : MarsUiState
    //...
}
  1. Perbarui fungsi getMarsPhotos() untuk meneruskan objek foto pertama Mars ke MarsUiState.Success(). Hapus variabel result.
marsUiState = try {
    MarsUiState.Success(marsPhotosRepository.getMarsPhotos()[0])
}
  1. Jalankan aplikasi dan konfirmasi bahwa aplikasi menampilkan satu gambar Mars.

d4421a2458f38695.png

  1. Foto Mars tidak memenuhi seluruh layar. Untuk mengisi ruang yang tersedia di layar, pada HomeScreen.kt di AsyncImage, atur contentScale ke ContentScale.Crop.
import androidx.compose.ui.layout.ContentScale

@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
   AsyncImage(
       model = ImageRequest.Builder(context = LocalContext.current)
           .data(photo.imgSrc)
           .crossfade(true)
           .build(),
       contentDescription = stringResource(R.string.mars_photo),
       contentScale = ContentScale.Crop,
       modifier = modifier,
   )
}
  1. Jalankan aplikasi dan konfirmasi bahwa gambar telah mengisi layar secara horizontal dan vertikal.

1b670f284109bbf5.png

Menambahkan gambar pemuatan dan error

Anda dapat meningkatkan kualitas pengalaman pengguna di aplikasi dengan menampilkan gambar placeholder saat memuat gambar. Anda juga dapat menampilkan gambar error jika pemuatan gagal karena masalah, seperti file gambar yang hilang atau rusak. Di bagian ini, Anda akan menambahkan gambar error dan placeholder menggunakan AsyncImage.

  1. Buka res/drawable/ic_broken_image.xml lalu klik tab Design atau Split di sebelah kanan. Untuk gambar error, gunakan ikon gambar rusak yang tersedia di library ikon bawaan. Vektor drawable ini menggunakan atribut android:tint untuk mewarnai ikon menjadi abu-abu.

70e008c63a2a1139.png

  1. Buka res/drawable/loading_img.xml. Drawable ini adalah animasi yang memutar drawable gambar, loading_img.xml, mengitari titik tengah. (Anda tidak melihat animasinya di pratinjau.)

92a448fa23b6d1df.png

  1. Kembali ke file HomeScreen.kt. Di composable MarsPhotoCard, perbarui panggilan ke AsyncImage() untuk menambahkan atribut error dan placeholder seperti yang ditunjukkan dalam kode berikut:
import androidx.compose.ui.res.painterResource

@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
    AsyncImage(
        // ...
        error = painterResource(R.drawable.ic_broken_image),
        placeholder = painterResource(R.drawable.loading_img),
        // ...
    )
}

Kode ini menetapkan gambar pemuatan placeholder yang akan digunakan saat memuat (drawable loading_img). Kode ini juga menetapkan gambar yang akan digunakan jika pemuatan gambar gagal (drawable ic_broken_image).

Composable MarsPhotoCard lengkap kini terlihat seperti kode berikut:

@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
    AsyncImage(
        model = ImageRequest.Builder(context = LocalContext.current)
            .data(photo.imgSrc)
            .crossfade(true)
            .build(),
        error = painterResource(R.drawable.ic_broken_image),
        placeholder = painterResource(R.drawable.loading_img),
        contentDescription = stringResource(R.string.mars_photo),
        contentScale = ContentScale.Crop
    )
}
  1. Jalankan aplikasi. Bergantung pada kecepatan koneksi jaringan, Anda mungkin melihat gambar pemuatan secara cepat saat Coil mendownload dan menampilkan gambar properti. Anda tidak akan melihat ikon gambar yang rusak meskipun jaringan dinonaktifkan—Anda akan memperbaiki error di tugas terakhir codelab.

d684b0e096e57643.gif

4. Menampilkan petak gambar dengan LazyVerticalGrid

Sekarang aplikasi Anda memuat foto Mars dari internet, item daftar MarsPhoto pertama. Anda telah menggunakan URL gambar dari data foto Mars tersebut untuk mengisi AsyncImage. Namun, tujuannya adalah agar aplikasi Anda menampilkan petak gambar. Dalam tugas ini, Anda menggunakan LazyVerticalGrid dengan pengelola tata letak Grid untuk menampilkan petak gambar.

Petak lambat

Composable LazyVerticalGrid dan LazyHorizontalGrid memberikan dukungan untuk menampilkan item dalam petak. Petak vertikal lambat menampilkan itemnya dalam penampung yang dapat di-scroll secara vertikal dan dibentangkan di beberapa kolom, sedangkan petak horizontal lambat memiliki perilaku yang sama pada sumbu horizontal.

27680e208333ed5.png

Dari perspektif desain, Tata Letak Grid paling tepat digunakan untuk menampilkan foto Mars sebagai ikon atau gambar.

Parameter columns di parameter LazyVerticalGrid dan rows di LazyHorizontalGrid mengontrol cara pembentukan sel menjadi kolom atau baris. Kode contoh berikut menampilkan item dalam petak, menggunakan GridCells.Adaptive untuk menetapkan lebar masing-masing kolom minimal 128.dp:

// Sample code - No need to copy over

@Composable
fun PhotoGrid(photos: List<Photo>) {
    LazyVerticalGrid(
        columns = GridCells.Adaptive(minSize = 150.dp)
    ) {
        items(photos) { photo ->
            PhotoItem(photo)
        }
    }
}

LazyVerticalGrid memungkinkan Anda menentukan lebar item, lalu petak akan sesuai dengan sebanyak mungkin kolom. Setelah menghitung jumlah kolom, petak akan mendistribusikan lebar yang tersisa di antara kolom secara merata. Cara adaptif pengukuran ini sangat berguna untuk menampilkan kumpulan item di berbagai ukuran layar.

Dalam codelab ini, Anda dapat menggunakan composable LazyVerticalGrid dengan GridCells.Adaptive, dengan setiap kolom ditetapkan ke lebar 150.dp, untuk menampilkan foto Mars.

Kunci item

Saat pengguna men-scroll petak (LazyRow dalam LazyColumn), posisi item daftar akan berubah. Namun, karena adanya perubahan orientasi atau jika item ditambahkan atau dihapus, pengguna dapat kehilangan posisi scroll dalam baris. Kunci item membantu Anda mempertahankan posisi scroll berdasarkan kunci.

Dengan menyediakan kunci, Anda membantu Compose menangani pengurutan ulang dengan benar. Misalnya, jika item Anda berisi status yang diingat, kunci setelan akan memungkinkan Compose memindahkan status ini bersama item tersebut saat posisinya berubah.

Menambahkan LazyVerticalGrid

Tambahkan composable untuk menampilkan daftar foto Mars dalam petak vertikal.

  1. Dalam file HomeScreen.kt, buat fungsi composable baru bernama PhotosGridScreen() yang menggunakan daftar MarsPhoto dan modifier sebagai argumen.
@Composable
fun PhotosGridScreen(
    photos: List<MarsPhoto>,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
) {
}
  1. Di dalam composable PhotosGridScreen, tambahkan LazyVerticalGrid dengan parameter berikut.
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.ui.unit.dp

@Composable
fun PhotosGridScreen(
    photos: List<MarsPhoto>,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
) {
    LazyVerticalGrid(
        columns = GridCells.Adaptive(150.dp),
        modifier = modifier.padding(horizontal = 4.dp),
        contentPadding = contentPadding,
   ) {
     }
}
  1. Untuk menambahkan daftar item, di dalam lambda LazyVerticalGrid, panggil fungsi items() yang meneruskan daftar MarsPhoto dan kunci item sebagai photo.id.
import androidx.compose.foundation.lazy.grid.items

@Composable
fun PhotosGridScreen(
    photos: List<MarsPhoto>,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
) {
   LazyVerticalGrid(
       // ...
   ) {
       items(items = photos, key = { photo -> photo.id }) {
       }
   }
}
  1. Untuk menambahkan konten yang ditampilkan oleh satu item daftar, tentukan ekspresi lambda items. Panggil MarsPhotoCard dengan meneruskan photo.
items(items = photos, key = { photo -> photo.id }) {
   photo -> MarsPhotoCard(photo)
}
  1. Perbarui composable HomeScreen untuk menampilkan composable PhotosGridScreen, bukan composable MarsPhotoCard, agar permintaan berhasil diselesaikan.
when (marsUiState) {
       // ...
       is MarsUiState.Success -> PhotosGridScreen(marsUiState.photos, modifier)
       // ...
}
  1. Dalam file MarsViewModel.kt, perbarui antarmuka MarsUiState untuk menerima daftar objek MarsPhoto, bukan MarsPhoto tunggal. Composable PhotosGridScreen menerima daftar objek MarsPhoto.
sealed interface MarsUiState {
    data class Success(val photos: List<MarsPhoto>) : MarsUiState
    //...
}
  1. Di file MarsViewModel.kt, perbarui fungsi getMarsPhotos() untuk meneruskan daftar objek foto Mars ke MarsUiState.Success().
marsUiState = try {
    MarsUiState.Success(marsPhotosRepository.getMarsPhotos())
}
  1. Jalankan aplikasi.

2eaec198c56b5eed.png

Perhatikan bahwa tidak ada padding di sekitar setiap foto, dan rasio aspek juga berbeda untuk foto yang berbeda. Anda dapat menambahkan composable Card untuk memperbaiki masalah ini.

Menambahkan composable card

  1. Di file HomeScreen.kt, di composable MarsPhotoCard, tambahkan Card dengan elevasi 8.dp di sekitar AsyncImage. Tetapkan argumen modifier ke composable Card.
import androidx.compose.material.Card
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.padding

@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {

    Card(
        modifier = modifier,
        elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
    ) {

        AsyncImage(
            model = ImageRequest.Builder(context = LocalContext.current)
                .data(photo.imgSrc)
                .crossfade(true)
                .build(),
            error = painterResource(R.drawable.ic_broken_image),
            placeholder = painterResource(R.drawable.loading_img),
            contentDescription = stringResource(R.string.mars_photo),
            contentScale = ContentScale.Crop,
            modifier = Modifier.fillMaxWidth()
        )
    }
}
  1. Untuk memperbaiki rasio aspek, di PhotosGridScreen(), perbarui pengubah untuk MarsPhotoCard().
@Composable
fun PhotosGridScreen(photos: List<MarsPhoto>, modifier: Modifier = Modifier) {
   LazyVerticalGrid(
       //...
   ) {
       items(items = photos, key = { photo -> photo.id }) { photo ->
           MarsPhotoCard(
               photo,
               modifier = modifier
                   .padding(4.dp)
                   .fillMaxWidth()
                   .aspectRatio(1.5f)
           )
       }
   }
}
  1. Perbarui pratinjau layar hasil untuk melihat pratinjau PhotosGridScreen(). Tirukan data dengan URL gambar kosong.
@Preview(showBackground = true)
@Composable
fun PhotosGridScreenPreview() {
   MarsPhotosTheme {
       val mockData = List(10) { MarsPhoto("$it", "") }
       PhotosGridScreen(mockData)
   }
}

Data tiruan memiliki URL kosong sehingga Anda akan melihat gambar yang dimuat di pratinjau petak foto.

Lakukan pratinjau pada pratinjau layar petak foto dengan gambar pemuatan

  1. Jalankan aplikasi.

b56acd074ce0f9c7.png

  1. Saat aplikasi berjalan, aktifkan Mode Pesawat.
  2. Scroll gambar di emulator. Gambar yang belum dimuat akan muncul sebagai ikon gambar yang rusak. Ini adalah drawable gambar yang telah Anda teruskan ke library gambar Coil untuk ditampilkan jika terjadi error jaringan atau gambar tidak bisa diambil.

9b72c1d4206c7331.png

Bagus! Anda telah menyimulasikan error koneksi jaringan dengan mengaktifkan Mode Pesawat di emulator atau perangkat.

5. Tambahkan tindakan coba lagi

Di bagian ini, Anda akan menambahkan tombol tindakan coba lagi dan mengambil foto saat tombol diklik.

60cdcd42bc540162.png

  1. Tambahkan tombol ke layar error. Dalam file HomeScreen.kt, update composable ErrorScreen() untuk menyertakan parameter lambda retryAction dan tombol.
@Composable
fun ErrorScreen(retryAction: () -> Unit, modifier: Modifier = Modifier) {
    Column(
        // ...
    ) {
        Image(
            // ...
        )
        Text(//...)
        Button(onClick = retryAction) {
            Text(stringResource(R.string.retry))
        }
    }
}

Periksa pratinjau.

55cf0c45f5be219f.png

  1. Perbarui composable HomeScreen() untuk meneruskan lambda coba lagi.
@Composable
fun HomeScreen(
   marsUiState: MarsUiState, retryAction: () -> Unit, modifier: Modifier = Modifier
) {
   when (marsUiState) {
       //...

       is MarsUiState.Error -> ErrorScreen(retryAction, modifier = modifier.fillMaxSize())
   }
}
  1. Pada file ui/theme/MarsPhotosApp.kt, update panggilan fungsi HomeScreen() untuk menetapkan parameter lambda retryAction ke marsViewModel::getMarsPhotos. Tindakan ini akan mengambil foto mars dari server.
HomeScreen(
   marsUiState = marsViewModel.marsUiState,
   retryAction = marsViewModel::getMarsPhotos
)

6. Memperbarui pengujian ViewModel

MarsUiState dan MarsViewModel kini mengakomodasi daftar foto, bukan hanya satu foto. Dalam statusnya saat ini, MarsViewModelTest mengharapkan class data MarsUiState.Success berisi properti string. Oleh karena itu, pengujian tidak dikompilasi. Anda harus memperbarui pengujian marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess() untuk menyatakan bahwa MarsViewModel.marsUiState sama dengan status Success yang berisi daftar foto.

  1. Buka file rules/MarsViewModelTest.kt.
  2. Pada pengujian marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess(), ubah panggilan fungsi assertEquals() untuk membandingkan status Success (meneruskan daftar foto palsu ke parameter foto) ke marsViewModel.marsUiState.
@Test
    fun marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess() =
        runTest {
            val marsViewModel = MarsViewModel(
                marsPhotosRepository = FakeNetworkMarsPhotosRepository()
            )
            assertEquals(
                MarsUiState.Success(FakeDataSource.photosList),
                marsViewModel.marsUiState
            )
        }

Sekarang pengujiannya bisa dikompilasi, berjalan, dan berhasil.

7. Mendapatkan kode solusi

Guna mendownload kode untuk codelab yang sudah selesai, Anda dapat menggunakan perintah git ini:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-mars-photos.git

Atau, Anda dapat mendownload repositori sebagai file ZIP, lalu mengekstraknya, dan membukanya di Android Studio.

Jika Anda ingin melihat kode solusi untuk codelab ini, lihat kode tersebut di GitHub.

8. Kesimpulan

Selamat karena telah menyelesaikan codelab ini dan membuat aplikasi Mars Photos. Kini saatnya memperlihatkan aplikasi Anda dengan gambar Mars nyata kepada keluarga dan teman Anda.

Jangan lupa untuk membagikan karya Anda di media sosial dengan #AndroidBasics!

9. Mempelajari lebih lanjut

Dokumentasi developer Android:

Lainnya: