Cómo migrar Jetpack Navigation a Navigation Compose

La API de Navigation Compose te permite navegar entre elementos componibles de una de Compose, y aprovecha el componente de Jetpack Navigation, la infraestructura y los atributos.

En esta página, se describe cómo migrar de Jetpack Navigation basado en fragmentos a Navigation Compose, como parte de la migración más amplia de IU basada en objetos View a Jetpack Compose

Requisitos previos para la migración

Podrás migrar a Navigation Compose una vez que puedas reemplazar todas tus Fragmentos con los elementos componibles de pantalla correspondientes. Los elementos componibles de pantalla pueden contener una combinación de contenido de Compose y View, pero todos los destinos de navegación deben estar elementos componibles para habilitar la migración de Navigation Compose. Hasta entonces, deberías continúas usando el componente de Navigation basado en fragmentos en tus elementos View de interoperabilidad Base de código de Compose. Consulta la documentación sobre interoperabilidad de navegación para obtener más información. información.

El uso de Navigation Compose en una app solo de Compose no es un requisito previo. Puedes sigue usando el componente Navigation basado en fragmentos, siempre y cuando mantengas Fragmentos para alojar tu contenido componible

Pasos de la migración

Ya sea que sigas nuestra estrategia de migración recomendada o estés tomando otro enfoque, llegará a un punto en el que todos los destinos de navegación elementos componibles de pantalla, con fragmentos que actúan solo como contenedores componibles En este puedes migrar a Navigation Compose.

Si tu app ya sigue un patrón de diseño de UDF y nuestra guía para de Terraform, migrar a Jetpack Compose y Navigation Compose no debería requieren refactorizaciones importantes de otras capas de tu app, además de la capa de la IU.

Para migrar a Navigation Compose, sigue estos pasos:

  1. Agrega la dependencia de Navigation Compose a tu app.
  2. Crea un elemento App-level componible y agrégalo a tu Activity como tu Punto de entrada de Compose, que reemplaza la configuración del diseño de View:

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

  3. Configura NavController en un lugar donde todos los elementos componibles necesiten para hacer referencia a ella tienen acceso a él (por lo general, está dentro de tu App componibles). Este enfoque sigue los principios de la elevación de estado y te permite usar NavController como fuente de confianza para navegar entre pantallas componibles y mantener la pila de actividades:

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

  4. Crea el elemento NavHost de tu app dentro del elemento componible App y pasa el navController:

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

  5. Agrega los destinos composable para compilar tu gráfico de navegación. Si cada se migró la pantalla previamente a Compose, este paso solo consiste en Extraer estos elementos componibles de pantalla de tus fragmentos en composable destinos:

    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 seguiste las instrucciones para diseñar la arquitectura de tu IU de Compose, sigue estos pasos: específicamente, cómo se deben pasar los ViewModel y los eventos de navegación componibles, el siguiente paso es cambiar la forma en que proporcionas el ViewModel a cada pantalla componible. A menudo, puedes usar la inyección de Hilt y su integración con Compose y Navigation a través de hiltViewModel:

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

  7. Reemplaza todas las llamadas de navegación findNavController() con navController. y pasarlos como eventos de navegación a cada pantalla componible, en lugar de que pasar todo el navController. Este enfoque sigue la mejor prácticas de exponer eventos de funciones de componibilidad a llamadores y mantiene el navController como la única fuente de confianza.

    1. Si ya usaste el complemento Safe Args para generar las instrucciones y acciones de navegación, reemplázalas por una ruta, una Es la ruta de acceso de la string al elemento componible que es única para cada destino.
    2. Para reemplazar Safe Args cuando se pasan datos, consulta Cómo navegar con argumentos.
    3. Para seguridad de tipos en Navigation Compose, lee la sección Safe Args. a continuación.

      @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. Elimina todos los fragmentos, los diseños XML relevantes, la navegación innecesaria y otros elementos. recursos y las dependencias inactivas de Fragment y Jetpack Navigation.

Puedes encontrar los mismos pasos con más detalles relacionados con Navigation Compose en el Documentación de la configuración.

Casos de uso comunes

Independientemente del componente Navigation que utilices, los mismos principios de de navegación.

Entre los casos de uso comunes durante la migración, se incluyen los siguientes:

Para obtener información más detallada sobre estos casos de uso, consulta Cómo navegar con Compose

Safe Args

A diferencia de Jetpack Navigation, Navigation Compose no admite el uso de Safe Complemento Args para la generación de código. En cambio, puedes lograr seguridad de tipos con Navigation Compose a través de la estructura del código para que tenga seguridad de tipos en tiempo de ejecución.

Recupera datos complejos durante la navegación

Navigation Compose se basa en rutas de cadenas y, a diferencia de Jetpack Navigation, realiza El permiso no admite el paso de objetos Parcelables y Serializables personalizados como argumentos.

Te recomendamos que no pases objetos de datos complejos durante la navegación. En su lugar, pasa la información mínima necesaria, como un identificador único o otra forma de ID, como argumentos cuando se realizan acciones de navegación. Deberías almacenar objetos complejos como datos en una única fuente de información, por ejemplo, los datos capa. Para obtener más información, consulta Recuperación de datos complejos cuando navegación.

Si tus fragmentos pasan objetos complejos como argumentos, considera refactorizar tu código primero, de manera que permita almacenar y recuperar estos objetos la capa de datos. Consulta el repositorio de Now in Android para ejemplos.

Limitaciones

En esta sección, se describen las limitaciones actuales de Navigation Compose.

Migración incremental a Navigation Compose

Actualmente, no puedes usar Navigation Compose mientras sigues usando Fragments como destinos en tu código. Para comenzar a usar Navigation Compose, todas tus los destinos deben ser componibles. Puedes realizar un seguimiento de esta solicitud de función en la Herramienta de seguimiento de errores.

Animaciones de transición

A partir de Navigation 2.7.0-alpha01, se admite la configuración personalizada de transición, que antes era de AnimatedNavHost, ahora es se admite directamente en NavHost. Lee las notas de la versión. para obtener más información.

Más información

Para obtener más información sobre cómo migrar a Navigation Compose, consulta lo siguiente: recursos:

  • Codelab de Navigation Compose: Aprende los conceptos básicos de Navigation Compose con un codelab práctico.
  • Repositorio de Now in Android: Una app para Android completamente funcional compilada por completo con Kotlin y Jetpack Compose, que sigue el diseño de Android y las prácticas recomendadas de desarrollo, e incluye Navigation Compose.
  • Cómo migrar Sunflower a Jetpack Compose: Una entrada de blog en la que se incluye documenta el recorrido de migración de la app de ejemplo de Sunflower desde Views hasta Compose, que también incluye la migración a Navigation Compose.
  • Jetnews for every screen: Una entrada de blog que documenta las refactorización y migración de la muestra de Jetnews para admitir todas las pantallas con Jetpack Compose y Navigation Compose.