Navigation vous permet d'associer des données à une opération de navigation en définissant des arguments pour une destination donnée. Par exemple, une destination de profil utilisateur peut utiliser un argument d'ID utilisateur pour déterminer l'utilisateur à afficher.
En général, il est fortement préférable de ne transmettre que la quantité minimale de données entre les destinations. Par exemple, vous devez transmettre une clé pour récupérer un objet plutôt que de transmettre l'objet lui-même, car l'espace total pour tous les états enregistrés est limité sur Android. Si vous devez transmettre de grandes quantités de données, utilisez un ViewModel
comme décrit dans la section Présentation de ViewModel.
Définir des arguments de destination
Pour transmettre des données entre les destinations, commencez par définir l'argument en l'ajoutant à la destination qui le reçoit. Procédez ainsi :
- Dans l'éditeur de navigation, cliquez sur la destination qui reçoit l'argument.
- Dans le panneau Attributes (Attributs), cliquez sur Add (+) (Ajouter).
- Dans la fenêtre Add Argument Link (Ajouter un lien d'argument) qui s'affiche, saisissez le nom de l'argument, son type, indiquez que la valeur est nullable et une valeur par défaut si nécessaire.
- Cliquez sur Add (Ajouter). Notez que l'argument apparaît maintenant dans la liste Arguments du panneau Attributes (Attributs).
- Cliquez ensuite sur l'action correspondante pour accéder à cette destination. Dans le panneau Attributes (Attributs), l'argument que vous venez d'ajouter doit maintenant apparaître dans la section Argument Default Values (Valeurs par défaut des arguments).
Vous pouvez également voir que l'argument a été ajouté en XML. Cliquez sur l'onglet Text (Texte) pour passer à la vue XML. Notez que votre argument a été ajouté à la destination qui le reçoit. Voici un exemple :
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
Types d'arguments pris en charge
La bibliothèque Navigation accepte les types d'arguments suivants :
Type | Syntaxe app:argType | Compatibilité avec les valeurs par défaut | Géré par des routes | Nullable |
---|---|---|---|---|
Nombre entier | app:argType="integer" | Oui | Oui | Non |
Float | app:argType="float" | Oui | Oui | Non |
Long | app:argType="long" | Oui. Les valeurs par défaut doivent toujours se terminer par le suffixe "L" (par exemple, "123L"). | Oui | Non |
Booléen | app:argType="boolean" | Oui. "true" ou "false" | Oui | Non |
Chaîne | app:argType="string" | Oui | Oui | Oui |
Référence de ressource | app:argType="reference" | Oui. Les valeurs par défaut doivent se présenter sous la forme "@resourceType/resourceName" (par exemple, "@style/myCustomStyle") ou "0". | Oui | Non |
Parcelable personnalisé | app:argType="<type>", où <type> est le nom complet de la classe de l'élément Parcelable |
Accepte la valeur par défaut "@null". Incompatible avec les autres valeurs par défaut. | Non | Oui |
Sérialisable personnalisé | app:argType="<type>", où <type> est le nom complet de la classe de l'élément Serializable |
Accepte la valeur par défaut "@null". Incompatible avec les autres valeurs par défaut. | Non | Oui |
Énumération personnalisée | app:argType="<type>", où <type> est le nom complet de l'énumération | Oui. Les valeurs par défaut doivent correspondre au nom non qualifié (par exemple, "SUCCESS" pour correspondre à MyEnum.SUCCESS). | Non | Non |
Si un type d'argument accepte les valeurs nulles, vous pouvez déclarer une valeur par défaut "null" en indiquant android:defaultValue="@null"
.
Les routes, les liens profonds et les URI avec leurs arguments peuvent être analysés à partir de chaînes. Cela n'est pas possible en utilisant des types de données personnalisés tels que des parcelables et des sérialisables, comme indiqué dans le tableau ci-dessus. Pour transmettre des données complexes personnalisées, stockez les données ailleurs (un ViewModel ou une base de données, par exemple) et ne transmettez un identifiant que pendant la navigation. Ensuite, récupérez les données au nouvel emplacement une fois la navigation terminée.
Lorsque vous choisissez l'un des types personnalisés, la boîte de dialogue Select Class (Sélectionner une classe) s'affiche et vous invite à choisir la classe correspondante pour ce type. L'onglet Project (Projet) vous permet de choisir une classe à partir de votre projet actuel.
Vous pouvez sélectionner <inferred type> pour que la bibliothèque Navigation détermine le type en fonction de la valeur fournie.
Vous pouvez cocher Array (Tableau) pour indiquer que l'argument doit être un tableau de la valeur Type sélectionnée. Remarques :
- Les tableaux d'énumérations et de références de ressources ne sont pas pris en charge.
- Les tableaux prennent en charge les valeurs nullables, quelles que soient les variables potentiellement nulles du type sous-jacent Par exemple, l'utilisation de
app:argType="integer[]"
vous permet d'utiliserapp:nullable="true"
pour indiquer qu'il est acceptable de transmettre un tableau nul. - Les tableaux ne prennent en charge qu'une seule valeur par défaut, à savoir "@null", Les tableaux n'acceptent aucune autre valeur par défaut.
Remplacer un argument de destination dans une action
Les arguments et les valeurs par défaut au niveau de la destination sont utilisés par toutes les actions qui permettent d'y accéder. Si nécessaire, vous pouvez remplacer la valeur par défaut d'un argument (ou en définir une, si ce n'est pas déjà fait) en définissant un argument au niveau de l'action. Celui-ci doit avoir le même nom et le même type que l'argument déclaré dans la destination.
Le code XML suivant reprend une action avec un argument qui force l'argument au niveau de la destination de l'exemple précédent :
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
Utiliser Safe Args pour transmettre des données avec sûreté du typage
Le composant Navigation dispose d'un plug-in Gradle appelé "Safe Args". Celui-ci génère des classes d'objets et de compilateurs simples pour une navigation sécurisée et l'accès à tous les arguments associés. Safe Args est vivement recommandé pour la navigation et la transmission de données, car il garantit la sûreté du typage.
Si vous n'utilisez pas Gradle, vous ne pouvez pas utiliser le plug-in Safe Args. Vous pouvez alors utiliser des bundles pour transmettre directement des données.
Pour ajouter Safe Args à votre projet, incluez le classpath
suivant dans votre fichier build.gradle
de premier niveau :
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.8.4" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.8.4" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
Vous devez également appliquer l'un des deux plug-ins disponibles.
Pour générer un code en langage Java adapté aux modules en Java ou mixant du Java et du Kotlin, ajoutez la ligne suivante au fichier build.gradle
de votre application ou module :
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Sinon, pour générer un code Kotlin adapté aux modules exclusivement en Kotlin, ajoutez la ligne suivante :
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
android.useAndroidX=true
doit figurer dans votre fichier gradle.properties
, tel qu'indiqué sur la page Migrer vers AndroidX.
Une fois que vous avez activé Safe Args, le code généré contient les classes et méthodes sûres suivantes pour chaque action, ainsi que pour chaque destination d'envoi et de réception.
Une classe est créée pour chaque destination à l'origine d'une action. Le nom de cette classe correspond au nom de la destination d'origine, auquel est ajouté le mot "Directions". Par exemple, si la destination d'origine est un fragment nommé
SpecifyAmountFragment
, la classe générée est appeléeSpecifyAmountFragmentDirections
.Cette classe dispose d'une méthode pour chaque action définie dans la destination d'origine.
Pour chaque action utilisée afin de transmettre l'argument, une classe interne est créée, et son nom est basé sur celle-ci. Par exemple, si l'action est appelée
confirmationAction,
, la classe est nomméeConfirmationAction
. Si votre action contient des arguments sansdefaultValue
, vous définissez la valeur des arguments à l'aide de la classe d'action associée.Une classe est créée pour la destination de réception. Le nom de cette classe est celui de la destination, suivi du mot "Args". Par exemple, si le fragment de destination est
ConfirmationFragment,
, la classe générée est nomméeConfirmationFragmentArgs
. Utilisez la méthodefromBundle()
de cette classe pour récupérer les arguments.
L'exemple suivant montre comment utiliser ces méthodes pour définir un argument et le transmettre à la méthode navigate()
:
Kotlin
override fun onClick(v: View) { val amountTv: EditText = view!!.findViewById(R.id.editTextAmount) val amount = amountTv.text.toString().toInt() val action = SpecifyAmountFragmentDirections.confirmationAction(amount) v.findNavController().navigate(action) }
Java
@Override public void onClick(View view) { EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount); int amount = Integer.parseInt(amountTv.getText().toString()); ConfirmationAction action = SpecifyAmountFragmentDirections.confirmationAction(); action.setAmount(amount); Navigation.findNavController(view).navigate(action); }
Dans le code de la destination de réception, utilisez la méthode getArguments()
pour récupérer le bundle et utiliser son contenu. Lorsqu'ils utilisent les dépendances -ktx
, les utilisateurs de Kotlin peuvent également utiliser le délégué de propriété by navArgs()
pour accéder aux arguments.
Kotlin
val args: ConfirmationFragmentArgs by navArgs() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tv: TextView = view.findViewById(R.id.textViewAmount) val amount = args.amount tv.text = amount.toString() }
Java
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { TextView tv = view.findViewById(R.id.textViewAmount); int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount(); tv.setText(amount + ""); }
Utiliser Safe Args avec une action globale
Lorsque vous utilisez Safe Args avec une action globale, vous devez fournir une valeur android:id
pour votre élément <navigation>
racine, comme dans cet exemple :
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main_nav" app:startDestination="@id/mainFragment"> ... </navigation>
La navigation génère une classe Directions
pour l'élément <navigation>
basée sur la valeur android:id
. Par exemple, si vous disposez d'un élément <navigation>
avec android:id=@+id/main_nav
, la classe générée est appelée MainNavDirections
. Toutes les destinations de l'élément <navigation>
ont généré des méthodes pour accéder à l'ensemble des actions globales associées à l'aide des mêmes méthodes que celles décrites dans la section précédente.
Transmettre des données entre des destinations avec des objets Bundle
Si vous n'utilisez pas Gradle, vous pouvez toujours transmettre des arguments entre les destinations à l'aide d'objets Bundle
. Créez un objet Bundle
et transmettez-le à la destination à l'aide de navigate()
, comme dans l'exemple suivant :
Kotlin
val bundle = bundleOf("amount" to amount) view.findNavController().navigate(R.id.confirmationAction, bundle)
Java
Bundle bundle = new Bundle(); bundle.putString("amount", amount); Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
Dans le code de votre destination, utilisez la méthode getArguments()
pour récupérer l'objet Bundle
et utiliser son contenu :
Kotlin
val tv = view.findViewById<TextView>(R.id.textViewAmount) tv.text = arguments?.getString("amount")
Java
TextView tv = view.findViewById(R.id.textViewAmount); tv.setText(getArguments().getString("amount"));
Transmettre les données à la destination de départ
Vous pouvez transmettre des données à la destination de départ de votre application. Tout d'abord, vous devez construire explicitement un objet Bundle
contenant les données. Ensuite, utilisez l'une des approches suivantes pour transmettre l'élément Bundle
à la destination de départ :
- Si vous créez votre composant
NavHost
de façon programmatique, appelezNavHostFragment.create(R.navigation.graph, args)
, oùargs
est leBundle
correspondant à l'objet contenant vos données. - Sinon, vous pouvez définir des arguments de destination de début en appelant l'une des surcharges suivantes de
NavController.setGraph()
:- Utiliser l'ID du graphique :
navController.setGraph(R.navigation.graph, args)
- Utiliser le graphique lui-même :
navController.setGraph(navGraph, args)
- Utiliser l'ID du graphique :
Pour récupérer les données de votre destination de départ, appelez Fragment.getArguments()
.
Remarques concernant ProGuard
Si vous réduisez votre code, vous devez empêcher l'obscurcissement des noms de classe Parcelable
, Serializable
et Enum
lors du processus de minimisation. Pour cela, deux possibilités s'offrent à vous :
- Utiliser les annotations @Keep
- Utiliser des règles keepnames
Ces approches sont décrites dans les sous-sections suivantes.
Utiliser les annotations @Keep
L'exemple suivant ajoute des annotations @Keep
aux définitions de classe de modèle :
Kotlin
@Keep class ParcelableArg : Parcelable { ... } @Keep class SerializableArg : Serializable { ... } @Keep enum class EnumArg { ... }
Java
@Keep public class ParcelableArg implements Parcelable { ... } @Keep public class SerializableArg implements Serializable { ... } @Keep public enum EnumArg { ... }
Utiliser des règles keepnames
Vous pouvez également ajouter des règles keepnames
à votre fichier proguard-rules.pro
, comme dans l'exemple suivant :
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
Ressources supplémentaires
Pour en savoir plus sur la navigation, consultez les ressources supplémentaires suivantes.