Navigation 3 representa un cambio fundamental en la forma en que Jetpack Compose controla el estado de navegación y ofrece ventajas arquitectónicas significativas en comparación con Navigation 2.
Comprende los cambios arquitectónicos y los pasos necesarios para migrar una app de Wear Compose de Navigation 2 a Navigation 3.
Ventajas clave de Navigation 3
- Control directo de la pila de actividades:
NavBackStackes, fundamentalmente, una lista mutable de objetosNavKeyque representa el historial de pantallas que visitó el usuario. Puedes controlarla exactamente como lo harías con cualquierMutableListde Kotlin (add,removeLast,clear). Manipulas directamente la lista para realizar acciones de navegación, como agregar una clave para avanzar o quitar una clave para retroceder. - Diseño Compose-First: La pila de actividades se modela como un estado observable estándar La modificación del historial de navegación se comporta exactamente como la actualización de cualquier otro estado de Compose, lo que activa automáticamente la recomposición para mostrar la pantalla actual.
- Tipo seguro de forma predeterminada: Se eliminan por completo las rutas basadas en cadenas. Navigation utiliza objetos de datos y clases de datos serializables.
- Presentaciones desacopladas (estrategias de escena): La capa de transición de la IU
(
NavDisplayySwipeDismissableSceneStrategy) está completamente separada del seguimiento de estado (NavBackStack), lo que permite una integración más simple de las transiciones de navegación integradas de Wear OS.
Pasos de la migración
1. Actualiza las dependencias
Quita la dependencia androidx.wear.compose:compose-navigation anterior y presenta las nuevas dependencias divididas de Navigation 3, junto con la compatibilidad con la serialización de Kotlin.
Quitar:
implementation("androidx.wear.compose:compose-navigation:...")
Agregar:
implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...") // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin
2. Actualiza los destinos para implementar NavKey
En Navigation 2, es posible que hayas usado cadenas o objetos genéricos para el enrutamiento. En
Navigation 3, debes implementar la interfaz de marcador NavKey y
anotar cada objeto de pantalla con @Serializable.
¿Por qué es necesario? Para garantizar que la pila de actividades se pueda guardar y
restablecer en el cierre del proceso, el navigation3-runtime subyacente se basa en
kotlinx-serialization para serializar el estado.
Antes (Navigation 2: Rutas genéricas de tipo seguro):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
Después (Navigation 3: NavKey + Serializable):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. Reemplaza la lógica de enrutamiento (NavController a NavBackStack)
Reemplaza tu NavController por un NavBackStack inicializado a través de
rememberNavBackStack. También debes crear una instancia de
SwipeDismissableSceneStrategy específicamente para Wear OS.
Antes (Navigation 2):
val navController = rememberSwipeDismissableNavController()
Después (Navigation 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. Reemplaza NavHost por NavDisplay y el DSL entryProvider
El contenedor NavHost y su compilador composable("route") { ... } interno
DSL se reemplazan por NavDisplay y el entryProvider {
entry<Key> { ... } } DSL.
Antes (Navigation 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
Después (Navigation 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )