Migrer la navigation Jetpack vers Navigation Compose

L'API Navigation Compose vous permet de naviguer entre les composables dans une application Compose, tout en tirant parti du composant, de l'infrastructure et des fonctionnalités de Jetpack Navigation.

Cette page explique comment migrer d'une navigation Jetpack basée sur des fragments vers Navigation Compose, dans le cadre de la migration d'UI plus large basée sur les vues vers Jetpack Compose.

Conditions préalables à la migration

Vous pouvez migrer vers Navigation Compose une fois que vous êtes en mesure de remplacer tous vos fragments par les composables d'écran correspondants. Les composables d'écran peuvent contenir une combinaison de contenus Compose et View, mais toutes les destinations de navigation doivent être des composables pour permettre la migration de Navigation Compose. En attendant, vous devez continuer à utiliser le composant Navigation basée sur des fragments dans votre vue d'interopérabilité et votre codebase Compose. Pour en savoir plus, consultez la documentation sur l'interopérabilité de la navigation.

L'utilisation de Navigation Compose dans une application Compose uniquement n'est pas une condition préalable. Vous pouvez continuer à utiliser le composant Navigation basée sur des fragments, tant que vous conservez des fragments pour héberger votre contenu composable.

Procédure de migration

Que vous suiviez notre stratégie de migration recommandée ou une autre approche, toutes les destinations de navigation seront des composables d'écran, les fragments n'étant que des conteneurs composables. À ce stade, vous pouvez migrer vers Navigation Compose.

Si votre application suit déjà un modèle de conception de l'UDF et notre guide de l'architecture, la migration vers Jetpack Compose et Navigation Compose ne devrait pas nécessiter de refactorisations majeures d'autres couches de votre application, en dehors de la couche de l'interface utilisateur.

Pour migrer vers Navigation Compose, procédez comme suit:

  1. Ajoutez la dépendance Compose Navigation à votre application.
  2. Créez un composable App-level et ajoutez-le à votre Activity en tant que point d'entrée Compose, en remplaçant la configuration de la mise en page View:

    class SampleActivity : ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample)
            setContent {
                SampleApp(/* ... */)
            }
        }
    }

  3. Configurez le NavController dans un endroit où tous les composables qui doivent le référencer ont accès (généralement dans votre composable App). Cette approche suit les principes du hissage d'état et vous permet d'utiliser NavController comme source fiable pour naviguer entre les écrans composables et maintenir la pile "Retour" :

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
        // ...
    }

  4. Créez le NavHost de votre application dans le composable Application et transmettez navController:

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
    
        SampleNavHost(navController = navController)
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = "first") {
            // ...
        }
    }

  5. Ajoutez les destinations composable pour créer votre graphique de navigation. Si chaque écran a déjà été migré vers Compose, cette étape consiste uniquement à extraire ces composables d'écran de vos fragments vers les destinations composable:

    class FirstFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            return ComposeView(requireContext()).apply {
                setContent {
                    // FirstScreen(...) EXTRACT FROM HERE
                }
            }
        }
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = "first") {
            composable("first") {
                FirstScreen(/* ... */) // EXTRACT TO HERE
            }
            composable("second") {
                SecondScreen(/* ... */)
            }
            // ...
        }
    }

  6. Si vous avez suivi les instructions de la section Concevoir l'architecture de votre UI Compose, en particulier la manière dont les ViewModel et les événements de navigation doivent être transmis aux composables, l'étape suivante consiste à modifier la façon dont vous fournissez le ViewModel à chaque composable d'écran. Vous pouvez souvent utiliser l'injection Hilt et son point d'intégration avec Compose et Navigation via hiltViewModel:

    @Composable
    fun FirstScreen(
        // viewModel: FirstViewModel = viewModel(),
        viewModel: FirstViewModel = hiltViewModel(),
        onButtonClick: () -> Unit = {},
    ) {
        // ...
    }

  7. Remplacez tous les appels de navigation findNavController() par les appels navController et transmettez-les en tant qu'événements de navigation à chaque écran composable, au lieu de transmettre l'intégralité de navController. Cette approche suit les bonnes pratiques qui consistent à exposer les événements de fonctions modulables aux appelants et conserve navController comme source unique de référence.

    1. Si vous avez déjà utilisé le plug-in Safe Args pour générer des itinéraires et des actions de navigation, remplacez-le par un route, c'est-à-dire un chemin d'accès de chaîne à votre composable qui est unique pour chaque destination.
    2. Pour remplacer Safe Args lors de la transmission de données, consultez la section Naviguer avec des arguments.
    3. Pour la sécurité du typage dans Navigation Compose, consultez la section Safe Args ci-dessous.

      @Composable
      fun SampleNavHost(
          navController: NavHostController
      ) {
          NavHost(navController = navController, startDestination = "first") {
              composable("first") {
                  FirstScreen(
                      onButtonClick = {
                          // findNavController().navigate(firstScreenToSecondScreenAction)
                          navController.navigate("second_screen_route")
                      }
                  )
              }
              composable("second") {
                  SecondScreen(
                      onIconClick = {
                          // findNavController().navigate(secondScreenToThirdScreenAction)
                          navController.navigate("third_screen_route")
                      }
                  )
              }
              // ...
          }
      }

  8. Supprimez tous les fragments, les mises en page XML pertinentes, la navigation et les autres ressources inutiles, ainsi que les dépendances obsolètes de Fragment et Jetpack Navigation.

Vous trouverez les mêmes étapes avec plus d'informations concernant Navigation Compose dans la documentation sur la configuration.

Cas d'utilisation courants

Quel que soit le composant de navigation que vous utilisez, les mêmes principes de navigation s'appliquent.

Voici quelques cas d'utilisation courants de la migration:

Pour en savoir plus sur ces cas d'utilisation, consultez la section Naviguer avec Compose.

Safe Args

Contrairement à Jetpack Navigation, Navigation Compose ne permet pas d'utiliser le plug-in Safe Args pour générer du code. À la place, vous pouvez assurer la sûreté du typage avec Navigation Compose en structurant votre code de sorte qu'il soit sûr lors de l'exécution.

Récupérer des données complexes lors de la navigation

Navigation Compose est basé sur des itinéraires de chaîne et, contrairement à Jetpack Navigation, ne prend pas en charge la transmission de Parcelables et Serializables personnalisés en tant qu'arguments.

Nous vous recommandons vivement de ne pas transmettre d'objets de données complexes lors de la navigation. Transmettez plutôt les informations minimales nécessaires, telles qu'un identifiant unique ou une autre forme d'ID, en tant qu'arguments lorsque vous effectuez des actions de navigation. Vous devez stocker des objets complexes en tant que données dans une source unique de référence, telle que la couche de données. Pour en savoir plus, consultez la section Récupérer des données complexes lors de la navigation.

Si vos fragments transmettent des objets complexes en tant qu'arguments, envisagez d'abord de refactoriser votre code, de manière à pouvoir stocker et récupérer ces objets de la couche de données. Consultez le dépôt Now in Android pour obtenir des exemples.

Limites

Cette section décrit les limites actuelles de Navigation Compose.

Migration incrémentielle vers Navigation Compose

Actuellement, vous ne pouvez pas utiliser Navigation Compose si vous utilisez des fragments comme destinations dans votre code. Pour commencer à utiliser Navigation Compose, toutes vos destinations doivent être des composables. Vous pouvez suivre cette demande de fonctionnalité dans l'outil Issue Tracker.

Animations de transition

À partir de Navigation 2.7.0-alpha01, la possibilité de définir des transitions personnalisées (auparavant depuis AnimatedNavHost) est désormais directement compatible avec NavHost. Pour en savoir plus, consultez les notes de version.

En savoir plus

Pour en savoir plus sur la migration vers Navigation Compose, consultez les ressources suivantes:

  • Atelier de programmation Navigation Compose: découvrez les principes de base de Navigation Compose avec un atelier pratique.
  • Now in Android dépôt (Maintenant dans le dépôt Android) : application Android entièrement fonctionnelle entièrement fonctionnelle avec Kotlin et Jetpack Compose, qui respecte les bonnes pratiques de conception et de développement Android et inclut Navigation Compose.
  • Migration de Sunflower vers Jetpack Compose: article de blog qui documente le parcours de migration de l'application exemple Sunflower des vues vers Compose, y compris la migration vers Navigation Compose.
  • Jetnews pour tous les écrans: article de blog qui documente la refactorisation et la migration de l'exemple Jetnews pour prendre en charge tous les écrans avec Jetpack Compose et Navigation Compose.