A navegação 3 representa uma mudança fundamental na forma como o Jetpack Compose processa o estado de navegação e oferece vantagens arquitetônicas significativas em relação à navegação 2.
Entenda as mudanças arquitetônicas e as etapas necessárias para migrar um app do Wear Compose da navegação 2 para a navegação 3.
Principais vantagens da navegação 3
- Controle direto da pilha de retorno: a
NavBackStacké fundamentalmente apenas uma lista mutável de objetosNavKey, que representa o histórico de telas que o usuário visitou. Você a controla exatamente como faria com qualquer KotlinMutableList(add,removeLast,clear). Você manipula diretamente a lista para realizar ações de navegação, como adicionar uma chave para avançar ou remover uma chave para voltar. - Design do Compose em primeiro lugar: a backstack é modelada como um estado observável padrão. A modificação do histórico de navegação se comporta exatamente como a atualização de qualquer outro estado do Compose, acionando automaticamente a recomposição para mostrar a tela atual.
- Segurança de tipos por padrão: as rotas baseadas em strings são eliminadas completamente. A navegação usa objetos de dados e classes de dados serializáveis.
- Apresentações desacopladas (estratégias de cena): a camada de transição da interface
(
NavDisplayeSwipeDismissableSceneStrategy) é totalmente separada do rastreamento de estado (NavBackStack), permitindo uma integração mais simples das transições de navegação integradas do Wear OS.
Etapas da migração
1. Atualizar dependências
Remova a dependência antiga androidx.wear.compose:compose-navigation e introduza as novas dependências divididas da navegação 3, além do suporte à serialização do Kotlin.
Remova:
implementation("androidx.wear.compose:compose-navigation:...")
Adicionar:
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. Atualizar destinos para implementar NavKey
Na navegação 2, você pode ter usado strings ou objetos genéricos para o roteamento. Na
navegação 3, é necessário implementar a interface de marcador NavKey e
anotar cada objeto de tela com @Serializable.
Por que isso é necessário? Para que a backstack possa ser salva e
restaurada durante o encerramento do processo, o navigation3-runtime subjacente depende de
kotlinx-serialization para serializar o estado.
Antes (navegação 2: rotas genéricas com segurança de tipos):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
Depois (navegação 3: NavKey + serializável):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. Substituir a lógica de roteamento (NavController para NavBackStack)
Substitua o NavController por uma NavBackStack inicializada usando
rememberNavBackStack. Você também precisa instanciar o
SwipeDismissableSceneStrategy especificamente para o Wear OS.
Antes (navegação 2):
val navController = rememberSwipeDismissableNavController()
Depois (navegação 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. Substituir NavHost por NavDisplay e a DSL entryProvider
O contêiner NavHost e a DSL do builder interno composable("route") { ... }
são substituídos por NavDisplay e a DSL entryProvider {
entry<Key> { ... } }.
Antes (navegação 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
Depois (navegação 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )