Esegui la migrazione a Navigazione 3

Navigation 3 rappresenta un cambiamento fondamentale nel modo in cui Jetpack Compose gestisce lo stato di navigazione e offre vantaggi architetturali significativi rispetto a Navigation 2.

Comprendi le modifiche all'architettura e i passaggi necessari per eseguire la migrazione di un'app Wear Compose da Navigation 2 a Navigation 3.

Vantaggi principali di Navigazione 3

  • Controllo diretto dello stack indietro: NavBackStack è fondamentalmente solo un elenco modificabile di oggetti NavKey, che rappresentano la cronologia delle schermate visitate dall'utente. Lo controlli esattamente come faresti con qualsiasi MutableList Kotlin (add, removeLast, clear). Manipoli direttamente l'elenco per eseguire azioni di navigazione, ad esempio aggiungendo un tasto per andare avanti o rimuovendo un tasto per tornare indietro.
  • Compose-First Design: il back stack è modellato come stato osservabile standard. La modifica della cronologia di navigazione si comporta esattamente come l'aggiornamento di qualsiasi altro stato di Compose, attivando automaticamente la ricomposizione per visualizzare lo schermo corrente.
  • Type-Safe by Default: le route basate su stringhe vengono eliminate completamente. La navigazione utilizza oggetti dati e classi di dati serializzabili.
  • Presentazioni disaccoppiate (strategie di scena): il livello di transizione dell'interfaccia utente (NavDisplay e SwipeDismissableSceneStrategy) è completamente separato dal monitoraggio dello stato (NavBackStack), consentendo un'integrazione più semplice delle transizioni di navigazione integrate di Wear OS.

Passi per la migrazione

1. Aggiorna le dipendenze

Rimuovi la vecchia dipendenza androidx.wear.compose:compose-navigation e introduci le nuove dipendenze di Navigation 3 suddivise, insieme al supporto della serializzazione Kotlin.

Rimuovi

implementation("androidx.wear.compose:compose-navigation:...")

Aggiungi:

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. Aggiorna le destinazioni per implementare NavKey

In Navigazione 2, potresti aver utilizzato stringhe o oggetti generici per il routing. In Navigation 3, devi implementare l'interfaccia marker NavKey e annotare ogni oggetto dello schermo con @Serializable.

Perché è necessario? Per garantire che lo stack precedente possa essere salvato e ripristinato in caso di interruzione del processo, navigation3-runtime sottostante si basa su kotlinx-serialization per serializzare lo stato.

Prima (Navigation 2 - Generic Type-Safe Routes):

sealed class Nav2Screen {
    data object Landing : Nav2Screen()
    data object List : Nav2Screen()
}

Dopo (Navigation 3 - NavKey + Serializable):

@Serializable
sealed interface MigrationScreen : NavKey {
    @Serializable
    data object Landing : MigrationScreen

    @Serializable
    data object List : MigrationScreen
}

3. Sostituisci la logica di routing (da NavController a NavBackStack)

Sostituisci NavController con un NavBackStack inizializzato tramite rememberNavBackStack. Devi anche creare un'istanza di SwipeDismissableSceneStrategy specificamente per Wear OS.

Prima (navigazione 2):

val navController = rememberSwipeDismissableNavController()

Dopo (navigazione 3):

val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey)
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

4. Sostituisci NavHost con NavDisplay e il DSL entryProvider

Il contenitore NavHost e il relativo DSL del builder composable("route") { ... } interno vengono sostituiti da NavDisplay e dal DSL entryProvider { entry<Key> { ... } }.

Prima (navigazione 2):

SwipeDismissableNavHost(navController = navController, startDestination = "menu") {
    composable("menu") {
        GreetingScreen(
            onShowList = { navController.navigate("list") }
        )
    }
    composable("list") {
        ListScreen()
    }
}

Dopo (navigazione 3):

NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        entry<MigrationScreen.Landing> {
            GreetingScreen(
                onShowList = { backStack.add(MigrationScreen.List) }
            )
        }
        entry<MigrationScreen.List> {
            ListScreen()
        }
    }
)