Pourquoi la navigation Android se casse : IllegalArgumentException et NavController

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

« Itinéraire perdu » : pourquoi Android Navigation Component devient fou

\n\n

Avez-vous déjà lancé votre application Android, navigué vers un écran, appuyé sur « Retour » — et soudain l’application plantait avec l’erreur IllegalArgumentException : navigation destination xxx is unknown to this NavController ? Si oui, vous n’êtes pas seul. Cette question a recueilli des milliers de vues sur Stack Overflow, et un développeur sur deux qui commence à travailler avec Jetpack Navigation y est confronté.

\n\n

Dans cet article, nous allons voir pourquoi l’IllegalArgumentException navigation destination unknown se produit, comment la diagnostiquer et, surtout, comment la corriger. Il y aura beaucoup de code vivant en Kotlin, des conseils pratiques et aucun « blabla ». C’est parti !

\n\n

Qu’est-ce que NavController et pourquoi « ne connaît-il pas » votre destination ?

\n\n

Pour commencer — un peu de théorie. NavController est le chef d’orchestre principal de la navigation sous Android. Il gère les transitions entre les écrans (fragments ou composables) sur la base du graphe de navigation — un fichier XML décrivant tous les itinéraires possibles. Lorsque vous appelez navController.navigate(R.id.some_destination), NavController recherche cet ID dans son graphe. S’il ne le trouve pas, il lance une IllegalArgumentException.

\n\n

Cela semble logique, mais pourquoi cela se produit-il à l’exécution et non à la compilation ? Parce que le graphe de navigation est chargé dynamiquement, et l’erreur est souvent liée au fait que le graphe actuel (celui que contient NavController) n’inclut tout simplement pas la destination demandée.

\n\n

Les scénarios d’erreur les plus fréquents

\n
    \n
  • Tentative de navigation vers un écran non décrit dans le graphe actuel — par exemple, vous changez de fragments alors que NavController provient du précédent.
  • \n
  • Utilisation de liens profonds (DeepLink) sans enregistrement correct — l’application est lancée via un lien, mais le graphe n’est pas encore chargé.
  • \n
  • Nettoyage de la pile arrière et tentative de navigation après cela — NavController « oublie » ses itinéraires.
  • \n
  • ID de destination incorrect — faute de frappe ou incohérence entre le nom dans le code et le XML.
  • \n
\n\n

Analyse sur un exemple réel (Kotlin)

\n\n

Imaginez que vous avez une application avec deux écrans : HomeFragment et ProfileFragment. Le graphe de navigation nav_graph.xml ressemble à ceci :

\n\n
<!-- nav_graph.xml -->\n<navigation xmlns:android="http://schemas.android.com/apk/res/android"\n    xmlns:app="http://schemas.android.com/apk/res-auto"\n    android:id="@+id/nav_graph"\n    app:startDestination="@id/homeFragment">\n\n    <fragment\n        android:id="@+id/homeFragment"\n        android:name="com.example.app.HomeFragment"\n        android:label="Home">\n        <action\n            android:id="@+id/action_home_to_profile"\n            app:destination="@id/profileFragment" />\n    </fragment>\n\n    <fragment\n        android:id="@+id/profileFragment"\n        android:name="com.example.app.ProfileFragment"\n        android:label="Profile" />\n</navigation>
\n\n

Dans HomeFragment, vous effectuez la transition :

\n\n
// HomeFragment.kt\nval navController = findNavController()\nnavController.navigate(R.id.action_home_to_profile)
\n\n

Tout fonctionne. Mais que se passe-t-il si vous essayez d’appeler navController.navigate(R.id.profileFragment) depuis un autre contexte — par exemple, depuis Activity ou BroadcastReceiver ? Ou si vous rechargez le graphe ? C’est là qu’apparaît l’IllegalArgumentException : navigation destination xxx is unknown to this NavController.

\n\n

Reproduire l’erreur

\n\n

Supposons que vous ayez ajouté un bouton « Retour » dans la barre d’outils et écrit ce code :

\n\n
// MainActivity.kt\nsupportActionBar?.setDisplayHomeAsUpEnabled(true)\n\noverride fun onOptionsItemSelected(item: MenuItem): Boolean                

Blogs

Book Recommendations