Activités et intents

1. Introduction

Jusqu'à présent, les applications sur lesquelles vous avez travaillé ne comptaient qu'une seule activité. En réalité, nombreuses sont les applications Android qui nécessitent plusieurs activités, avec une navigation entre elles.

Dans cet atelier de programmation, vous créerez une application de dictionnaire afin qu'elle utilise plusieurs activités et des intents, et qu'elle transmette des données à d'autres applications.

Conditions préalables

Vous devez être en mesure d'effectuer les actions suivantes :

  • Parcourir un projet dans Android Studio.
  • Utiliser et ajouter des ressources XML dans Android Studio.
  • Remplacer et implémenter des méthodes dans une classe existante.
  • Créer des instances de classes Kotlin et accéder à leurs propriétés et méthodes d'appel.
  • Vous reporter à la documentation sur developer.android.com pour en savoir plus sur des classes spécifiques.

Points abordés

Vous découvrirez comment effectuer les actions suivantes :

  • Utiliser un intent explicite pour accéder à une activité spécifique.
  • Utiliser un intent implicite pour accéder au contenu d'une autre application.
  • Inclure des options de menu pour ajouter des boutons à la barre d'application.

Objectifs de l'atelier

  • Modifier une application de dictionnaire afin d'implémenter la navigation entre les écrans à l'aide d'intents et en ajoutant un menu d'options.

Ce dont vous avez besoin

  • Un ordinateur sur lequel est installé Android Studio.

2. Code de démarrage

Au cours des prochaines étapes, vous travaillerez sur l'application Words. Il s'agit d'une application de dictionnaire simple, avec une liste de lettres, des mots pour chaque lettre et la possibilité de rechercher des définitions de chaque mot dans le navigateur.

Elle est assez complexe, mais ne vous inquiétez pas : vous n'aurez pas besoin de créer l'application entière pour vous familiariser avec les intents. À la place, vous avez à votre disposition une version incomplète du projet, que l'on appelle aussi "projet d'initiation".

Bien que tous les écrans soient implémentés, vous ne pouvez pas encore passer d'un écran à l'autre. Votre tâche consiste à utiliser des intents pour que l'ensemble du projet fonctionne, sans avoir à tout créer de zéro.

Télécharger le code de démarrage pour cet atelier de programmation

Cet atelier de programmation fournit un code de démarrage que vous pouvez étendre avec les fonctionnalités qui y sont enseignées. Le code de démarrage peut contenir du code que vous avez déjà vu dans les ateliers de programmation précédents. Il peut également comporter du code que vous ne connaissez pas et que vous découvrirez dans d'autres ateliers.

Lorsque vous téléchargerez le code de démarrage depuis GitHub, notez que le nom du dossier est android-basics-kotlin-words-app-starter. Sélectionnez ce dossier lorsque vous ouvrirez le projet dans Android Studio.

Si vous connaissez les commandes git, notez que le code de démarrage se trouve dans une branche appelée "starter". Après avoir cloné le dépôt, vérifiez le code de la branche origin/starter. Si vous n'avez jamais utilisé les commandes git, suivez les étapes ci-dessous pour télécharger le code depuis GitHub.

  1. Accédez à la page du dépôt GitHub fournie pour le projet.
  2. Vérifiez que le nom de la branche correspond à celui spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.

1e4c0d2c081a8fd2.png

  1. Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.

1debcf330fd04c7b.png

  1. Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
  2. Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
  3. Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.

Ouvrir le projet dans Android Studio

  1. Lancez Android Studio.
  2. Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).

d8e9dbdeafe9038a.png

Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).

8d1fda7396afe8e5.png

  1. Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
  2. Double-cliquez sur le dossier de ce projet.
  3. Attendez qu'Android Studio ouvre le projet.
  4. Cliquez sur le bouton Run (Exécuter) 8de56cba7583251f.png pour compiler et exécuter l'appli. Assurez-vous que tout fonctionne comme prévu.

3. Présentation de l'application Words

Avant de continuer, prenez le temps de vous familiariser avec le projet. Vous devriez déjà connaître tous les concepts grâce aux modules précédents. À ce stade, l'application se compose de deux activités, chacune dotée d'une vue recycleur et d'un adaptateur.

61af34429128695e.png

Vous allez utiliser les fichiers suivants :

  1. LetterAdapter est utilisé par RecyclerView dans MainActivity. Chaque lettre correspond à un bouton avec un élément onClickListener, qui est actuellement vide. C'est là que vous gérerez les pressions de bouton permettant d'accéder à DetailActivity.
  2. WordAdapter est utilisé par RecyclerView dans DetailActivity pour afficher une liste de mots. Bien que vous ne puissiez pas encore accéder à cet écran, sachez simplement que chaque mot est associé à un bouton avec un élément onClickListener. C'est ici que vous ajouterez le code qui permettra d'accéder au navigateur afin d'afficher la définition du mot.
  3. MainActivity nécessitera également quelques modifications. C'est là que vous implémenterez le menu d'options afin d'afficher un bouton permettant aux utilisateurs de basculer entre les mises en page "Liste" et "Grille".

ce3474dba2a9c1c8.png

Lorsque vous vous serez suffisamment familiarisé avec le projet, passez à la section suivante, dans laquelle vous découvrirez les intents.

4. Présentation des intents

Maintenant que vous avez configuré le projet initial, examinons les intents et voyons comment les utiliser dans votre application.

Un intent est un objet représentant une action quelconque à effectuer. Il sert le plus souvent à lancer une activité, mais bien d'autres utilisations sont possibles. Il existe deux types d'intents : implicite et explicite. L'intent explicite est très spécifique. Il connaît l'activité exacte à lancer, souvent un écran de votre propre application.

L'intent implicite est un peu plus abstrait, car il indique au système le type d'action (par exemple, ouvrir un lien, rédiger un e-mail ou passer un appel téléphonique) et c'est au système de déterminer comment répondre à cette requête. Vous avez probablement déjà vu les deux types d'intents à l'œuvre sans le savoir. Généralement, lorsque vous affichez une activité dans votre propre application, vous faites appel à un intent explicite.

Toutefois, pour les actions qui n'impliquent pas nécessairement l'application actuelle (par exemple, si vous avez trouvé une page de documentation Android intéressante et que vous souhaitez la partager avec des amis), vous devez utiliser un intent implicite. Un menu de ce type peut s'afficher, vous demandant quelle application utiliser pour partager la page.

e9c77033d9224170.png

Un intent explicite permet d'effectuer des actions ou de présenter des écrans dans votre propre application. Vous êtes responsable de l'ensemble du processus. Les intents implicites sont couramment utilisés pour réaliser des actions impliquant d'autres applications. Dans ce cas, c'est le système qui détermine le résultat final. Vous utiliserez les deux types d'intents dans l'application Words.

702236c6e2276f91.png

5. Configurer un intent explicite

L'heure est venue d'implémenter le premier intent. Sur le premier écran, lorsque l'utilisateur appuie sur une lettre, il doit être redirigé vers un second écran contenant une liste de mots. DetailActivity est déjà implémenté. Il vous suffit donc de le lancer avec un intent. Étant donné que l'application sait exactement quelle activité lancer, vous utiliserez un intent explicite.

Pour créer et utiliser un intent, quelques étapes suffisent :

  1. Ouvrez LetterAdapter.kt et faites défiler l'écran jusqu'à onBindViewHolder(). Sous la ligne permettant de définir le texte du bouton, définissez l'élément onClickListener pour holder.button.
holder.button.setOnClickListener {

}
  1. Effectuez ensuite une référence à context.
val context = holder.itemView.context
  1. Créez un Intent en transmettant le contexte et le nom de classe de l'activité de destination.
val intent = Intent(context, DetailActivity::class.java)

Le nom de l'activité que vous souhaitez afficher est indiqué par DetailActivity::class.java. Un objet DetailActivity réel est créé en arrière-plan.

  1. Appelez la méthode putExtra, en indiquant "letter" comme premier argument et le texte du bouton comme deuxième argument.
intent.putExtra("letter", holder.button.text.toString())

Qu'est-ce qu'un extra ? N'oubliez pas qu'un intent n'est qu'un ensemble d'instructions. Il n'existe pas encore d'instance de l'activité de destination. Un extra est une donnée, tel qu'un nombre ou une chaîne, à laquelle un nom à récupérer ultérieurement est attribué. Il s'apparente à la transmission d'un argument lorsque vous appelez une fonction. Étant donné que DetailActivity peut être affiché pour n'importe quelle lettre, vous devez lui indiquer la lettre à présenter.

Pourquoi pensez-vous qu'il est nécessaire d'appeler toString() ? Après tout, le texte du bouton est déjà une chaîne.

Plus ou moins. Il s'agit d'une interface, de type CharSequence. À ce stade, vous n'avez pas besoin de tout savoir sur les interfaces Kotlin, sauf pour vérifier qu'un type, tel que String, met en œuvre des fonctions et des propriétés spécifiques. Vous pouvez considérer l'élément CharSequence comme une représentation plus générique d'une classe semblable à une chaîne. La propriété text d'un bouton peut être une chaîne ou n'importe quel objet qui est également un élément CharSequence. En revanche, la méthode putExtra() accepte un élément String, et non n'importe quel élément CharSequence, d'où la nécessité d'appeler toString().

  1. Appelez la méthode startActivity() au niveau l'objet "context" et transmettez intent.
context.startActivity(intent)

Exécutez maintenant l'application et essayez d'appuyer sur une lettre. L'écran de détails s'affiche. Cependant, quelle que soit la lettre sur laquelle l'utilisateur appuie, l'écran de détails affiche toujours les mots correspondant à la lettre A. Il vous reste du travail à effectuer dans l'activité de détail afin que l'application affiche les mots correspondant à la lettre transmise en tant qu'extra intent.

6. Configurer DetailActivity

Vous venez de créer votre premier intent explicite. Passons maintenant à l'écran de détails.

Dans la méthode onCreate de DetailActivity, après l'appel de setContentView, remplacez la lettre codée en dur par le code pour que letterId soit transmis à partir de intent.

val letterId = intent?.extras?.getString("letter").toString()

Beaucoup d'éléments entrent en jeu ici. Examinons chaque partie :

Tout d'abord, d'où provient la propriété intent ? Il ne s'agit pas d'une propriété DetailActivity, mais plutôt d'une propriété correspondant à n'importe quelle activité. Elle conserve une référence à l'intent utilisé pour lancer l'activité.

La propriété "extras" est de type Bundle et, comme vous l'avez peut-être deviné, permet d'accéder à tous les extras transmis à l'intent.

Ces deux propriétés sont signalées par un point d'interrogation. Pourquoi ? Parce que les propriétés intent et extras peuvent être nullables, ce qui signifie qu'elles peuvent avoir ou non une valeur. Il peut arriver que vous souhaitiez qu'une variable soit null. La propriété intent n'est pas forcément un Intent (si l'activité n'a pas été lancée à partir d'un intent) et la propriété "extras" n'est pas forcément un Bundle, mais plutôt une valeur appelée null. En langage Kotlin, null signifie l'absence de valeur. L'objet peut exister ou peut correspondre à null. Si votre application tente d'accéder à une propriété ou d'appeler une fonction au niveau d'un objet null, elle plante. Pour accéder en toute sécurité à cette valeur, vous devez insérer un signe ? après le nom. Si intent est défini sur null, votre application n'essaiera pas d'accéder à la propriété "extras" et, si extras est "null", le code n'essaiera pas d'appeler getString().

Comment savoir quelles propriétés nécessitent un point d'interrogation pour garantir la sécurité null ? Vous pouvez le déterminer si le nom du type est suivi d'un point d'interrogation ou d'un point d'exclamation.

b43155b06a5556e.png

Le dernier point à noter est que la lettre réelle est récupérée avec getString, qui renvoie String?. toString() est donc appelé pour s'assurer qu'il s'agit d'un élément String, et non d'une valeur null.

Lorsque vous exécutez l'application et que vous accédez à l'écran de détails, la liste des mots doit s'afficher pour chaque lettre.

c465ef280fe3792a.png

Nettoyage

Le code permettant d'exécuter l'intent et de récupérer la lettre sélectionnée code en dur le nom de l'extra, "letter". Même si cette approche fonctionne pour cet exemple de petite envergure, il ne s'agit pas de la meilleure approche pour les applications volumineuses pour lesquelles vous avez beaucoup plus d'extras "intent" à suivre.

Bien que vous puissiez simplement créer une constante appelée "letter", cela peut devenir pénible lorsque vous ajoutez des extras "intent" à votre application. Se pose aussi la question de savoir dans quelle classe placer cette constante. N'oubliez pas que la chaîne est utilisée à la fois dans DetailActivity et dans MainActivity. Vous avez besoin d'un moyen de définir une constante pouvant être utilisée dans plusieurs classes, tout en conservant le code organisé.

Heureusement, une fonctionnalité Kotlin particulièrement utile permet de séparer les constantes et de les rendre utilisables sans instance spécifique de la classe. On parle alors d'objets compagnons. Un objet compagnon est semblable aux autres objets, comme les instances d'une classe. Cependant, il n'existe qu'une seule instance d'un objet compagnon pendant la durée de votre programme. C'est pourquoi on parle parfois de modèle singleton. Bien qu'il existe de nombreux cas d'utilisation de singletons qui ne sont pas couverts dans cet atelier de programmation, pour le moment, vous utiliserez un objet compagnon pour organiser les constantes et les rendre accessibles en dehors de DetailActivity. Vous commencerez par utiliser un objet compagnon pour refactoriser le code de l'extra "letter".

  1. Dans DetailActivity, juste au-dessus de onCreate, ajoutez le code suivant :
companion object {

}

Notez que cette méthode est semblable à la définition d'une classe, sauf que vous utilisez le mot clé object. Il existe également un mot clé companion, qui est associé à la classe DetailActivity. Il n'est donc pas nécessaire de lui attribuer un nom de type distinct.

  1. Ajoutez une propriété pour la constante "letter" entre les accolades.
const val LETTER = "letter"
  1. Pour utiliser la nouvelle constante, mettez à jour l'appel de la lettre codée en dur dans onCreate() comme suit :
val letterId = intent?.extras?.getString(LETTER).toString()

Là aussi, notez que vous la référencez avec une notation par points comme d'habitude, mais que la constante appartient à DetailActivity.

  1. Passez à LetterAdapter et modifiez l'appel de putExtra pour utiliser la nouvelle constante.
intent.putExtra(DetailActivity.LETTER, holder.button.text.toString())

Et voilà ! Grâce à la refactorisation, vous venez de rendre le code plus facile à lire et à gérer. Si vous deviez apporter des modifications à cette constante ou à une autre, il vous suffirait de le faire à un seul endroit.

Pour en savoir plus sur les objets compagnons, consultez la documentation Kotlin sur les expressions et déclarations d'objet.

7. Configurer un intent implicite

Dans la plupart des cas, vous présenterez des activités spécifiques provenant de votre propre application. Toutefois, il peut arriver que vous ne sachiez pas quelle activité ou quelle application vous souhaitez lancer. Dans l'écran de détails, chaque mot correspond à un bouton qui affiche la définition du mot.

Dans notre exemple, vous utiliserez la fonctionnalité de dictionnaire fournie par une recherche Google. Toutefois, au lieu d'ajouter une activité à l'application, vous ouvrirez le navigateur de l'appareil pour afficher la page de recherche.

Peut-être avez-vous besoin d'un intent pour charger la page dans Chrome, le navigateur par défaut sur Android ?

Pas tout à fait.

Il se peut que certains utilisateurs préfèrent un navigateur tiers. Ou peut-être un navigateur spécifique a-t-il été préinstallé sur leur téléphone par le fabricant. Peut-être l'application de recherche Google est-elle déjà installée, voire une application de dictionnaire tierce.

Vous ne pouvez pas savoir avec certitude quelles applications l'utilisateur a installées. Vous ne pouvez pas non plus savoir comment il va procéder pour rechercher un mot. Cet exemple illustre parfaitement l'utilisation d'un intent implicite. Votre application fournit des informations au système sur l'action à effectuer. Le système détermine l'action à effectuer et invite ainsi l'utilisateur à fournir des informations supplémentaires si nécessaire.

Procédez comme suit pour créer l'intent implicite :

  1. Pour cette application, vous rechercherez un mot dans la recherche Google. Le premier résultat sera une définition fournie par un dictionnaire. Comme la même URL de base sera utilisée pour chaque recherche, nous vous recommandons de la définir comme étant sa propre constante. Dans DetailActivity, modifiez l'objet compagnon pour ajouter une constante, SEARCH_PREFIX. Il s'agit de l'URL de base d'une recherche Google.
companion object {
   const val LETTER = "letter"
   const val SEARCH_PREFIX = "https://www.google.com/search?q="
}
  1. Ensuite, ouvrez WordAdapter et, dans la méthode onBindViewHolder(), appelez setOnClickListener() au niveau du bouton. Commencez par créer un Uri pour la requête de recherche. Lorsque vous appelez parse() pour créer un Uri à partir d'un élément String, vous devez utiliser une mise en forme de chaîne afin que le mot soit ajouté à SEARCH_PREFIX.
holder.button.setOnClickListener {
    val queryUrl: Uri = Uri.parse("${DetailActivity.SEARCH_PREFIX}${item}")
}

Si vous vous demandez ce qu'est un URI, sachez qu'il ne s'agit pas d'une faute de frappe. Cet acronyme signifie Uniform Resource Identifier (Identifiant de ressource uniforme). Vous savez peut-être déjà qu'une URL (ou Uniform Resource Locator) est une chaîne qui renvoie vers une page Web. Un URI est un terme plus général pour désigner le format. Toutes les URL sont des URI, mais pas tous les URI sont des URL. Les autres URI, tels que l'adresse correspondant à un numéro de téléphone, commencent par tel:, mais sont considérés comme un URN, Uniform Resource Name, plutôt que comme une URL. Le type de données utilisé pour représenter les deux s'appelle URI.

828cef3fdcfdaed.png

Notez qu'il n'existe ici aucune référence à des activités spécifiques dans votre propre application. Il suffit de fournir un URI, sans indiquer la manière dont il sera utilisé.

  1. Après avoir défini queryUrl, initialisez un nouvel objet intent :
val intent = Intent(Intent.ACTION_VIEW, queryUrl)

Au lieu de transmettre un contexte et une activité, transmettez Intent.ACTION_VIEW avec l'URI.

ACTION_VIEW est un intent générique qui accepte un URI (dans votre cas, une adresse Web). Le système sait alors qu'il devra traiter cet intent en ouvrant cet URI dans le navigateur Web de l'utilisateur. Voici d'autres types d'intents :

  • CATEGORY_APP_MAPS : lancement de l'application de cartographie
  • CATEGORY_APP_EMAIL : lancement de l'application de messagerie
  • CATEGORY_APP_GALLERY : lancement de l'application de galerie (photos)
  • ACTION_SET_ALARM : configuration d'une alarme en arrière-plan
  • ACTION_DIAL : passer un appel téléphonique

Pour en savoir plus, consultez la documentation sur les intents couramment utilisés.

  1. Enfin, même si vous ne lancez aucune activité particulière dans votre application, vous demandez au système de lancer une autre application en appelant startActivity() et en transmettant intent.
context.startActivity(intent)

À présent, lorsque vous lancerez l'application, accédez à la liste de mots, puis appuyez sur l'un d'eux. L'appareil devrait accéder à l'URL (ou présenter une liste d'options en fonction des applications installées).

Le comportement exact variera en fonction des utilisateurs, ce qui offrira une expérience fluide à tous, sans compliquer le code.

8. Configurer le menu et les icônes

Maintenant que vous avez rendu votre application entièrement navigable en ajoutant des intents explicites et implicites, vous allez ajouter une option de menu afin que l'utilisateur puisse passer d'une mise en page "Liste" à une mise en page "Grille" pour les lettres.

Comme vous l'avez sûrement remarqué, de nombreuses applications affichent cette barre en haut de l'écran. C'est ce qu'on appelle la barre d'application. En plus d'afficher le nom de l'application, elle peut être personnalisée et héberger de nombreuses fonctionnalités utiles, telles que des raccourcis pour des actions utiles ou des menus à développer.

dfc4095251c1466e.png

Pour cette application, nous n'allons pas ajouter un menu complet, mais vous découvrirez comment ajouter un bouton personnalisé à la barre d'application pour permettre à l'utilisateur de modifier la mise en page.

  1. Commencez par importer deux icônes pour représenter la vue Grille et la vue Liste. Ajoutez les ressources vectorielles clipart appelées "view module" (appelez-la ic_grid_layout) et "view list" (appelez-la ic_linear_layout). Si vous ne vous rappelez plus comment ajouter des icônes Material, consultez les instructions de cette page.

5a01fc03113ac399.png

  1. Vous devez également indiquer au système les options à afficher dans la barre d'application et les icônes à utiliser. Pour ce faire, ajoutez un fichier de ressource en effectuant un clic droit sur le dossier res, puis sélectionnez New > Android Resource File (Nouveau > Fichier de ressources Android). Définissez le type de ressource sur Menu et le nom de fichier sur layout_menu.

c4f83806a1aa121b.png

  1. Cliquez sur OK.
  2. Ouvrez res/Menu/layout_menu. Remplacez le contenu de layout_menu.xml par le code suivant :
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item android:id="@+id/action_switch_layout"
       android:title="@string/action_switch_layout"
       android:icon="@drawable/ic_linear_layout"
       app:showAsAction="always" />
</menu>

La structure du fichier de menu est assez simple. Tout comme une mise en page commence par un gestionnaire de mise en page contenant des vues individuelles, un fichier XML de menu commence par une balise de menu, qui contient des options spécifiques.

Votre menu ne comporte qu'un seul bouton, avec quelques propriétés :

  • id : tout comme les vues, l'option de menu possède un identifiant qui permet de la référencer dans le code.
  • title : ce texte n'est pas visible dans votre cas, mais il peut être utile pour permettre aux lecteurs d'écran d'identifier le menu.
  • icon : la valeur par défaut est ic_linear_layout. Toutefois, cette option sera activée et désactivée pour afficher l'icône Grille lorsque le bouton sera sélectionné.
  • showAsAction : indique au système comment afficher le bouton. Comme il est défini sur "always" (toujours), ce bouton reste visible dans la barre d'application et ne peut pas faire partie d'un menu à développer.

La simple définition des propriétés ne signifie pas que le menu fonctionnera.

Pour que le menu fonctionne, vous devez ajouter du code dans MainActivity.kt.

9. Implémenter le bouton Menu

Pour voir le bouton du menu en action, plusieurs opérations sont nécessaires dans MainActivity.kt.

  1. Tout d'abord, nous vous recommandons de créer une propriété pour suivre l'état de mise en page dans lequel se trouve l'application. Il sera ainsi plus facile d'activer et de désactiver le bouton de mise en page. Définissez la valeur par défaut sur true, car le gestionnaire de mise en page linéaire sera utilisé par défaut.
private var isLinearLayoutManager = true
  1. Vous voulez que la liste des éléments s'affiche sous forme de grille lorsque l'utilisateur appuie sur le bouton. Si vous vous rappelez ce que vous avez appris sur les vues de recyclage, il existe de nombreux gestionnaires de mise en page différents. L'un d'eux, GridLayoutManager, permet d'insérer plusieurs éléments sur une même ligne.
private fun chooseLayout() {
    if (isLinearLayoutManager) {
        recyclerView.layoutManager = LinearLayoutManager(this)
    } else {
        recyclerView.layoutManager = GridLayoutManager(this, 4)
    }
    recyclerView.adapter = LetterAdapter()
}

Ici, vous utiliserez une instruction if pour attribuer le gestionnaire de mise en page. En plus de définir layoutManager, ce code assigne également l'adaptateur. LetterAdapter est utilisé pour les mises en page sous forme de grille et de liste.

  1. Lorsque vous avez initialement configuré le menu au format XML, vous lui avez attribué une icône statique. Toutefois, après avoir modifié la mise en page, vous devez mettre à jour cette icône pour refléter sa nouvelle fonction, qui consiste à revenir à la mise en page précédente. Dans ce cas, il suffit de définir les icônes de mise en page linéaire et en grille en fonction de la mise en page à laquelle le bouton passera la prochaine fois qu'un utilisateur appuiera dessus.
private fun setIcon(menuItem: MenuItem?) {
   if (menuItem == null)
       return

   // Set the drawable for the menu icon based on which LayoutManager is currently in use

   // An if-clause can be used on the right side of an assignment if all paths return a value.
   // The following code is equivalent to
   // if (isLinearLayoutManager)
   //     menu.icon = ContextCompat.getDrawable(this, R.drawable.ic_grid_layout)
   // else menu.icon = ContextCompat.getDrawable(this, R.drawable.ic_linear_layout)
   menuItem.icon =
       if (isLinearLayoutManager)
           ContextCompat.getDrawable(this, R.drawable.ic_grid_layout)
       else ContextCompat.getDrawable(this, R.drawable.ic_linear_layout)
}

L'icône est définie de manière conditionnelle en fonction de la propriété isLinearLayoutManager.

Pour que votre application puisse réellement utiliser le menu, vous devez remplacer deux autres méthodes.

  • onCreateOptionsMenu : permet de gonfler le menu d'options et d'effectuer toute configuration supplémentaire.
  • onOptionsItemSelected : permet d'appeler chooseLayout() lorsque le bouton est sélectionné.
  1. Remplacez onCreateOptionsMenu comme suit :
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   menuInflater.inflate(R.menu.layout_menu, menu)

   val layoutButton = menu?.findItem(R.id.action_switch_layout)
   // Calls code to set the icon based on the LinearLayoutManager of the RecyclerView
   setIcon(layoutButton)

   return true
}

Ce processus est plutôt standard. Après avoir gonflé la mise en page, appelez setIcon() pour vous assurer que l'icône est correcte, en fonction de la mise en page. La méthode renvoie un élément Boolean. Vous devez renvoyer true ici, car vous souhaitez que le menu d'options soit créé.

  1. Implémentez onOptionsItemSelected avec seulement quelques lignes de code supplémentaires, comme illustré ci-dessous.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
   return when (item.itemId) {
       R.id.action_switch_layout -> {
           // Sets isLinearLayoutManager (a Boolean) to the opposite value
           isLinearLayoutManager = !isLinearLayoutManager
           // Sets layout and icon
           chooseLayout()
           setIcon(item)

           return true
       }
       //  Otherwise, do nothing and use the core event handling

       // when clauses require that all possible paths be accounted for explicitly,
       //  for instance both the true and false cases if the value is a Boolean,
       //  or an else to catch all unhandled cases.
       else -> super.onOptionsItemSelected(item)
   }
}

Cette fonction est appelée chaque fois que l'utilisateur appuie sur un élément de menu. Il est donc important de déterminer l'élément de menu sur lequel l'utilisateur devra appuyer. Utilisez une instruction when, au-dessus. Si id correspond à l'élément de menu action_switch_layout, vous neutralisez la valeur de l'élément isLinearLayoutManager. Appelez ensuite chooseLayout() et setIcon() pour mettre à jour l'UI en conséquence.

Il reste une dernière chose à faire avant d'exécuter l'application. Comme le gestionnaire de mise en page et l'adaptateur sont désormais définis dans chooseLayout(), vous devez remplacer ce code dans onCreate() afin d'appeler la nouvelle méthode. Une fois la modification effectuée, onCreate() devrait se présenter comme suit :

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)

   val binding = ActivityMainBinding.inflate(layoutInflater)
   setContentView(binding.root)

   recyclerView = binding.recyclerView
   // Sets the LinearLayoutManager of the recyclerview
   chooseLayout()
}

Exécutez votre application. Vous devriez pouvoir passer de la vue Liste à la vue Grille, et vice versa, à l'aide du bouton Menu.

10. Code de solution

Le code de solution de cet atelier de programmation figure dans le projet ci-dessous :

  1. Accédez à la page du dépôt GitHub fournie pour le projet.
  2. Vérifiez que le nom de la branche correspond à celui spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.

1e4c0d2c081a8fd2.png

  1. Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.

1debcf330fd04c7b.png

  1. Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
  2. Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
  3. Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.

Ouvrir le projet dans Android Studio

  1. Lancez Android Studio.
  2. Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).

d8e9dbdeafe9038a.png

Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).

8d1fda7396afe8e5.png

  1. Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
  2. Double-cliquez sur le dossier de ce projet.
  3. Attendez qu'Android Studio ouvre le projet.
  4. Cliquez sur le bouton Run (Exécuter) 8de56cba7583251f.png pour créer et exécuter l'application. Assurez-vous qu'elle fonctionne correctement.

11. Résumé

  • Les intents explicites permettent d'accéder à des activités spécifiques dans votre application.
  • Les intents implicites correspondent à des actions spécifiques (comme ouvrir un lien ou partager une image) et laissent le système déterminer comment les traiter.
  • Les options de menu vous permettent d'ajouter des boutons et des menus à la barre d'application.
  • Les objets compagnons permettent d'associer des constantes réutilisables à un type plutôt qu'une instance de ce type.

Pour exécuter un intent :

  • Effectuez une référence au contexte.
  • Créez un objet Intent qui fournit un type d'activité ou d'intent (selon qu'il est explicite ou implicite).
  • Transmettez toutes les données nécessaires en appelant putExtra().
  • Appelez startActivity() en transmettant l'objet intent.

12. En savoir plus