Charger et afficher des images depuis Internet

1. Avant de commencer

Introduction

Dans de précédents ateliers de programmation, vous avez appris à extraire des données d'un service Web à l'aide d'un schéma de dépôt et à analyser la réponse dans un objet Kotlin. Dans cet atelier, vous allez vous appuyer sur ces connaissances pour charger et afficher des photos à partir d'une adresse URL. Vous verrez également à nouveau comment créer une LazyVerticalGrid et l'utiliser pour afficher une grille d'images sur la page de présentation.

Conditions préalables

  • Savoir récupérer des fichiers JSON à partir d'un service Web REST et analyser ces données dans des objets Kotlin à l'aide des bibliothèques Retrofit et Gson
  • Avoir des connaissances sur le service Web REST
  • Avoir de bonnes connaissances sur les composants d'architecture Android, comme la couche de données et le dépôt
  • Avoir des connaissances sur l'injection de dépendances
  • Avoir des connaissances sur ViewModel et ViewModelProvider.Factory
  • Avoir des connaissances sur l'implémentation de coroutines pour votre application
  • Avoir des connaissances sur le schéma de dépôt

Points abordés

  • Comment utiliser la bibliothèque Coil pour charger et afficher une image à partir d'une adresse URL
  • Comment utiliser une LazyVerticalGrid pour afficher une grille d'images
  • Comment gérer les erreurs qui peuvent survenir lorsque les images se téléchargent et s'affichent

Objectifs de l'atelier

  • Modifier l'application Mars Photos pour obtenir l'URL de l'image à partir des données de Mars, puis utiliser Coil pour charger et afficher cette image
  • Ajouter une animation de chargement et une icône d'erreur à l'application
  • Ajouter un état et une gestion des erreurs à l'application

Ce dont vous avez besoin

  • Un ordinateur doté d'un navigateur Web récent (par exemple, la dernière version de Chrome)
  • Le code de démarrage de l'application Mars Photos avec les services Web REST

2. Présentation de l'application

Dans cet atelier de programmation, vous allez utiliser l'application Mars Photos d'un atelier précédent. Cette application se connecte à un service Web pour récupérer les objets Kotlin et afficher leur nombre à l'aide de Gson. Ces objets Kotlin contiennent les URL des photos réelles de la surface de Mars prises par les rovers de la NASA.

a59e55909b6e9213.png

La version de l'application que vous créez dans cet atelier de programmation affiche les photos de Mars dans une grille d'images. Les images font partie des données que l'application récupère à partir du service Web. Cette application utilise la bibliothèque Coil pour charger et afficher les images, ainsi que LazyVerticalGrid pour les mettre en page sous la forme d'une grille. Elle affiche aussi un message d'erreur pratique en cas d'erreur réseau.

68f4ff12cc1e2d81.png

Télécharger le code de démarrage

Pour commencer, téléchargez le code de démarrage :

Vous pouvez également cloner le dépôt GitHub du code :

$ 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

Vous pouvez parcourir le code dans le dépôt GitHub Mars Photos.

3. Afficher une image téléchargée

Même si afficher une photo à partir d'une URL peut sembler simple, plusieurs opérations sont nécessaires pour que cela fonctionne correctement. Vous devez télécharger l'image, la stocker dans la mémoire interne (en cache) et décoder son format compressé pour récupérer une image compatible avec Android. Vous pouvez la mettre en cache dans la mémoire, sur un support de stockage, voire dans les deux. Toutes ces opérations doivent être réalisées dans des threads en arrière-plan de faible priorité afin que l'UI reste réactive. Pour optimiser les performances du réseau et du processeur, vous pouvez également extraire et décoder plusieurs images à la fois.

Heureusement, vous pouvez utiliser Coil, une bibliothèque développée par la communauté, pour télécharger, mettre en mémoire tampon, décoder et mettre en cache vos images. Si vous décidez de vous passer de Coil, vous aurez beaucoup plus de travail.

Coil a besoin de deux choses :

  • L'URL de l'image que vous voulez charger et afficher
  • Un composable AsyncImage pour afficher réellement cette image

Dans cette tâche, vous allez apprendre à utiliser Coil pour afficher une seule image à partir du service Web Mars. Vous afficherez l'image de la photo de Mars figurant en premier dans la liste renvoyée par le service Web. Vous trouverez ci-dessous des captures d'écran avant et après :

a59e55909b6e9213.png 1b670f284109bbf5.png

Ajouter la dépendance Coil

  1. Ouvrez l'application Mars Photos de l'atelier de programmation Ajouter un dépôt et injecter manuellement des dépendances.
  2. Exécutez-la pour vérifier qu'elle affiche bien le nombre de photos de Mars récupérées.
  3. Ouvrez build.gradle.kts (Module :app).
  4. Dans la section dependencies (dépendances), ajoutez la ligne suivante pour la bibliothèque Coil :
// Coil
implementation("io.coil-kt:coil-compose:2.4.0")

Sur la page de documentation de la bibliothèque Coil, vérifiez quelle est la dernière version et faites la mise à jour.

  1. Cliquez sur Sync now (Synchroniser) pour recréer le projet avec la nouvelle dépendance.

Afficher l'URL de l'image

Au cours de cette étape, vous allez récupérer et afficher l'URL de la première photo de Mars.

  1. Dans ui/screens/MarsViewModel.kt, recherchez dans le bloc try de la méthode getMarsPhotos() la ligne qui définit les données extraites du service Web sur listResult.
// No need to copy, code is already present
try {
   val listResult = marsPhotosRepository.getMarsPhotos()
   //...
}
  1. Modifiez cette ligne en remplaçant listResult par result et en affectant la première photo de Mars récupérée à la nouvelle variable result. Affectez l'objet de la première photo à l'index 0.
try {
   val result = marsPhotosRepository.getMarsPhotos()[0]
   //...
}
  1. Sur la ligne suivante, remplacez le paramètre transmis à l'appel de fonction MarsUiState.Success() par la chaîne figurant dans le code ci-dessous. Utilisez les données de la nouvelle propriété au lieu de listResult. Affichez l'URL de la première image issue du result de la photo.
try {
   ...
   MarsUiState.Success("First Mars image URL: ${result.imgSrc}")
}

Le bloc try complet se présente maintenant comme suit :

marsUiState = try {
   val result = marsPhotosRepository.getMarsPhotos()[0]
   MarsUiState.Success(
       "   First Mars image URL : ${result.imgSrc}"
   )
}
  1. Exécutez l'application. Le composable Text affiche désormais l'URL de la première photo de Mars. La prochaine section explique comment faire en sorte que l'application affiche l'image de cette URL.

b5daaa892fe8dad7.png

Ajouter un composable AsyncImage

Au cours de cette étape, vous allez ajouter une fonction modulable AsyncImage pour charger et afficher une seule photo de Mars. AsyncImage est un composable qui exécute une requête d'image de manière asynchrone et qui affiche le résultat.

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

L'argument model peut être soit la valeur ImageRequest.data, soit l'ImageRequest proprement dite. Dans l'exemple de code précédent, vous allez attribuer la valeur ImageRequest.data (c'est-à-dire l'URL de l'image, qui est "https://android.com/sample_image.jpg"). L'exemple de code ci-dessous montre comment attribuer la valeur ImageRequest proprement dite au 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 prend en charge les mêmes arguments que le composable Image standard. Il permet également de définir des peintures placeholder/error/fallback et des rappels onLoading/onSuccess/onError. L'exemple de code précédent charge l'image avec un recadrage dans un cercle et un fondu enchaîné, et définit un espace réservé.

contentDescription définit le texte utilisé par les services d'accessibilité pour décrire ce que cette image représente.

Ajoutez un composable AsyncImage à votre code pour afficher la première photo de Mars récupérée.

  1. Dans ui/screens/HomeScreen.kt, ajoutez une fonction modulable intitulée MarsPhotoCard(), qui accepte MarsPhoto et Modifier.
@Composable
fun MarsPhotoCard(photo: MarsPhoto, modifier: Modifier = Modifier) {
}
  1. Dans la fonction modulable MarsPhotoCard(), ajoutez la fonction AsyncImage() comme suit :
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()
    )
}

Dans le code précédent, vous allez créer une ImageRequest avec l'URL de l'image (photo.imgSrc) et la transmettre à l'argument model. contentDescription permet de définir le texte des lecteurs d'accessibilité.

  1. Ajoutez crossfade(true) à ImageRequest pour activer une animation en fondu enchaîné lorsque la requête aboutit.
@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. Modifiez le composable HomeScreen pour qu'il affiche le composable MarsPhotoCard au lieu du composable ResultScreen lorsque la requête aboutit. Vous allez corriger l'erreur de non-correspondance de type à la prochaine étape.
@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. Dans le fichier MarsViewModel.kt, modifiez l'interface MarsUiState pour qu'elle accepte un objet MarsPhoto au lieu d'un objet String.
sealed interface MarsUiState {
    data class Success(val photos: MarsPhoto) : MarsUiState
    //...
}
  1. Modifiez la fonction getMarsPhotos() pour qu'elle transmette l'objet de la première photo de Mars à MarsUiState.Success(). Supprimez la variable result.
marsUiState = try {
    MarsUiState.Success(marsPhotosRepository.getMarsPhotos()[0])
}
  1. Exécutez l'application et vérifiez qu'elle affiche bien une seule image de Mars.

d4421a2458f38695.png

  1. La photo de Mars n'occupe pas tout l'écran. Pour qu'elle occupe l'espace disponible, dans HomeScreen.kt sous AsyncImage, définissez contentScale sur 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. Exécutez l'application, et vérifiez que l'image occupe tout l'écran horizontalement et verticalement.

1b670f284109bbf5.png

Ajouter des images de chargement et d'erreur

Vous pouvez améliorer l'expérience utilisateur dans votre application en affichant un espace réservé pour une image lorsqu'elle se charge. Vous pouvez également afficher une image d'erreur si le chargement échoue (par exemple, à cause d'un fichier image manquant ou corrompu). Dans cette section, vous allez ajouter à la fois des images d'erreur et d'espace réservé à l'aide de AsyncImage.

  1. Ouvrez res/drawable/ic_broken_image.xml, puis cliquez sur l'onglet Design (Conception) ou Split (Diviser) à droite. Pour l'image d'erreur, utilisez l'icône d'image défectueuse disponible dans la bibliothèque d'icônes intégrée. Ce drawable vectoriel utilise l'attribut android:tint pour colorer l'icône en gris.

70e008c63a2a1139.png

  1. Ouvrez res/drawable/loading_img.xml. Ce drawable est une animation qui fait pivoter une image drawable, loading_img.xml, autour de son point central. (L'animation ne s'affiche pas dans l'aperçu.)

92a448fa23b6d1df.png

  1. Revenez au fichier HomeScreen.kt. Dans le composable MarsPhotoCard, modifiez l'appel à AsyncImage() pour ajouter les attributs error et placeholder, comme indiqué dans le code ci-dessous :
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),
        // ...
    )
}

Ce code définit l'image de chargement de l'espace réservé à utiliser lors du chargement (le drawable loading_img). Il définit également l'image à utiliser en cas d'échec du chargement (le drawable ic_broken_image).

Le composable MarsPhotoCard complet se présente maintenant comme suit :

@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. Exécutez l'application. Selon la vitesse de votre connexion réseau, vous pouvez voir brièvement l'image de chargement pendant que Coil télécharge et affiche l'image de propriété. Toutefois, pour le moment, l'icône représentant une image défectueuse ne s'affichera pas même si vous désactivez votre réseau. Vous allez résoudre ce problème dans la dernière tâche de cet atelier de programmation.

d684b0e096e57643.gif

4. Afficher une grille d'images avec LazyVerticalGrid

Votre application charge désormais une photo de Mars depuis Internet (le premier élément de la liste MarsPhoto). Vous avez utilisé l'URL de l'image issue des données de cette photo de Mars pour insérer une AsyncImage. Toutefois, l'objectif est que votre application affiche une grille d'images. Au cours de cette tâche, vous allez utiliser une LazyVerticalGrid avec un gestionnaire de mise en page adapté pour afficher une grille d'images.

Grilles différées

Les composables LazyVerticalGrid et LazyHorizontalGrid permettent d'afficher des éléments dans une grille. Une grille verticale différée affiche ses éléments dans un conteneur à faire défiler verticalement, s'étendant sur plusieurs colonnes, tandis qu'une grille horizontale différée a le même comportement sur l'axe horizontal.

27680e208333ed5.png

Du point de vue de la conception, la mise en page sous la forme de grille est idéale pour afficher des photos de Mars représentées par des icônes ou des images.

Les paramètres columns dans LazyVerticalGrid et rows dans LazyHorizontalGrid contrôlent la manière dont les cellules sont formées dans des colonnes ou des lignes. L'exemple de code ci-dessous affiche des éléments dans une grille, en utilisant GridCells.Adaptive pour définir chaque colonne sur une largeur d'au moins 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 vous permet de spécifier une largeur pour les éléments. La grille s'adapte ensuite au plus grand nombre de colonnes possible. Une fois le nombre de colonnes calculé, la grille répartit équitablement les largeurs restantes entre les colonnes. Cette méthode de dimensionnement adaptative est particulièrement utile pour afficher des ensembles d'éléments sur différentes tailles d'écran.

Dans cet atelier de programmation, pour afficher des photos de Mars, vous allez utiliser le composable LazyVerticalGrid avec GridCells.Adaptive et une largeur de 150.dp pour chaque colonne.

Clés d'élément

Lorsque l'utilisateur fait défiler la grille (une LazyRow dans un LazyColumn), la position de l'élément de liste change. Toutefois, en raison d'un changement d'orientation, voire de l'ajout ou de la suppression d'éléments, l'utilisateur peut perdre la position de défilement sur la ligne. Les clés associées aux éléments vous aident à conserver la position de défilement en fonction de la clé.

En fournissant des clés, vous aidez Compose à gérer les réorganisations correctement. Par exemple, si votre élément contient un état mémorisé, les clés permettent à Compose de déplacer cet état avec l'élément lorsque sa position change.

Ajouter LazyVerticalGrid

Ajoutez un composable pour afficher une liste de photos de Mars dans une grille verticale.

  1. Dans le fichier HomeScreen.kt, créez une fonction modulable intitulée PhotosGridScreen(), qui utilise une liste de MarsPhoto et un modifier comme arguments.
@Composable
fun PhotosGridScreen(
    photos: List<MarsPhoto>,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
) {
}
  1. Dans le composable PhotosGridScreen, ajoutez une LazyVerticalGrid avec les paramètres suivants.
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. Pour ajouter une liste d'éléments, dans le lambda LazyVerticalGrid, appelez la fonction items() qui transmet la liste de MarsPhoto et la clé d'élément 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. Pour ajouter le contenu affiché par un seul élément de liste, définissez l'expression lambda items. Appelez MarsPhotoCard en transmettant la photo.
items(items = photos, key = { photo -> photo.id }) {
   photo -> MarsPhotoCard(photo)
}
  1. Modifiez le composable HomeScreen pour afficher le composable PhotosGridScreen au lieu du composable MarsPhotoCard lorsque la requête aboutit.
when (marsUiState) {
       // ...
       is MarsUiState.Success -> PhotosGridScreen(marsUiState.photos, modifier)
       // ...
}
  1. Dans le fichier MarsViewModel.kt, modifiez l'interface MarsUiState pour accepter une liste d'objets MarsPhoto au lieu d'un seul objet MarsPhoto. Le composable PhotosGridScreen accepte une liste d'objets MarsPhoto.
sealed interface MarsUiState {
    data class Success(val photos: List<MarsPhoto>) : MarsUiState
    //...
}
  1. Dans le fichier MarsViewModel.kt, modifiez la fonction getMarsPhotos() pour transmettre une liste d'objets de photo de Mars à MarsUiState.Success().
marsUiState = try {
    MarsUiState.Success(marsPhotosRepository.getMarsPhotos())
}
  1. Exécutez l'application.

2eaec198c56b5eed.png

Notez qu'il n'y a pas de marge intérieure autour de chaque photo et que le format diffère selon les photos. Vous pouvez ajouter un composable Card pour résoudre ces problèmes.

Ajouter un composable Card

  1. Dans le fichier HomeScreen.kt, puis dans le composable MarsPhotoCard, ajoutez une fonction Card avec une élévation de 8.dp autour de AsyncImage. Attribuez l'argument modifier au 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. Pour corriger le format, dans PhotosGridScreen(), redéfinissez le modificateur pour 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. Modifiez l'aperçu de l'écran de résultats pour prévisualiser PhotosGridScreen(). Simulez les données avec des URL d'images vides.
@Preview(showBackground = true)
@Composable
fun PhotosGridScreenPreview() {
   MarsPhotosTheme {
       val mockData = List(10) { MarsPhoto("$it", "") }
       PhotosGridScreen(mockData)
   }
}

Étant donné que les données fictives contiennent des URL vides, des images de chargement sont affichées dans l'aperçu de la grille de photos.

Aperçu de l'écran prévisualisant la grille de photos avec l'image de chargement

  1. Exécutez l'application.

b56acd074ce0f9c7.png

  1. Pendant l'exécution de l'application, activez le mode Avion.
  2. Faites défiler les images dans l'émulateur. À la place des images qui n'ont pas encore été chargées, des icônes d'images défectueuses s'affichent. Il s'agit de l'image drawable que vous avez transmise à la bibliothèque d'images Coil et qui s'affiche si une erreur réseau survient ou si une image ne peut pas être extraite.

9b72c1d4206c7331.png

Bien joué ! Vous avez simulé une erreur de connexion réseau en activant le mode Avion dans votre émulateur ou sur votre appareil.

5. Ajouter un bouton "Réessayer"

Dans cette section, vous ajouterez un bouton d'action "Réessayer" afin de récupérer les photos lorsque l'utilisateur clique sur celui-ci.

60cdcd42bc540162.png

  1. Ajoutez un bouton à l'écran d'erreur. Dans le fichier HomeScreen.kt, modifiez le composable ErrorScreen() pour inclure un paramètre lambda retryAction et un bouton.
@Composable
fun ErrorScreen(retryAction: () -> Unit, modifier: Modifier = Modifier) {
    Column(
        // ...
    ) {
        Image(
            // ...
        )
        Text(//...)
        Button(onClick = retryAction) {
            Text(stringResource(R.string.retry))
        }
    }
}

Vérifier l'aperçu

55cf0c45f5be219f.png

  1. Modifiez le composable HomeScreen() pour transmettre le lambda de nouvelle tentative.
@Composable
fun HomeScreen(
   marsUiState: MarsUiState, retryAction: () -> Unit, modifier: Modifier = Modifier
) {
   when (marsUiState) {
       //...

       is MarsUiState.Error -> ErrorScreen(retryAction, modifier = modifier.fillMaxSize())
   }
}
  1. Dans le fichier ui/theme/MarsPhotosApp.kt, modifiez l'appel de fonction HomeScreen() pour définir le paramètre lambda retryAction sur marsViewModel::getMarsPhotos. Les photos de Mars seront ainsi récupérées sur le serveur.
HomeScreen(
   marsUiState = marsViewModel.marsUiState,
   retryAction = marsViewModel::getMarsPhotos
)

6. Modifier le test ViewModel

MarsUiState et MarsViewModel acceptent désormais une liste de photos au lieu d'une seule photo. Dans son état actuel, MarsViewModelTest s'attend à ce que la classe de données MarsUiState.Success contienne une propriété de chaîne. Par conséquent, le test n'est pas compilé. Vous devez modifier le test marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess() pour indiquer que MarsViewModel.marsUiState est égal à l'état Success contenant la liste de photos.

  1. Ouvrez le fichier rules/MarsViewModelTest.kt.
  2. Dans le test marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess(), modifiez l'appel de fonction assertEquals() pour comparer un état Success (en transmettant la liste de photos fictives au paramètre photos) à marsViewModel.marsUiState.
@Test
    fun marsViewModel_getMarsPhotos_verifyMarsUiStateSuccess() =
        runTest {
            val marsViewModel = MarsViewModel(
                marsPhotosRepository = FakeNetworkMarsPhotosRepository()
            )
            assertEquals(
                MarsUiState.Success(FakeDataSource.photosList),
                marsViewModel.marsUiState
            )
        }

Le test est à présent compilé, exécuté et conclu.

7. Télécharger le code de solution

Pour télécharger le code de l'atelier de programmation terminé, utilisez la commande Git suivante :

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

Vous pouvez également télécharger le dépôt sous forme de fichier ZIP, le décompresser et l'ouvrir dans Android Studio.

Si vous le souhaitez, vous pouvez consulter le code de solution de cet atelier de programmation sur GitHub.

8. Conclusion

Bravo ! Vous avez terminé cet atelier de programmation, et l'application Mars Photos est prête à l'emploi. Il est temps d'en profiter pour montrer de vraies photos de Mars à vos proches.

N'oubliez pas de partager le fruit de vos efforts sur les réseaux sociaux avec le hashtag #AndroidBasics.

9. En savoir plus

Documentation pour les développeurs Android :

Autre :