0Pricing
Android Academy · Aula

Navegação entre módulos

Conecte recursos sem criar acoplamento.

Navegação entre módulos é uma aula grátis de Android Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Android Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Android Academy inclui 4 aulas no total.

O desafio da navegação

Quando as funcionalidades vivem em módulos separados, surge uma nova pergunta: como :feature:home abre uma tela em :feature:profile sem depender dele? Se as funcionalidades importarem umas às outras diretamente, você terá acoplamento e correrá o risco de criar ciclos.

Nesta lição, você conectará as funcionalidades por meio da navegação, mantendo-as independentes.

Onde fica o NavHost

O único NavHost fica no módulo :app, o único lugar autorizado a conhecer todas as funcionalidades. Cada funcionalidade contribui com seus destinos, e o :app os reúne em um único grafo.

// app/AppNavHost.kt
@Composable
fun AppNavHost(navController: NavHostController = rememberNavController()) {
    NavHost(navController, startDestination = HomeRoute) {
        homeScreen(onProfileClick = { navController.navigate(ProfileRoute) })
        profileScreen(onBack = { navController.popBackStack() })
    }
}

Rotas seguras quanto aos tipos

O Navigation Compose moderno oferece suporte a rotas seguras quanto aos tipos: uma rota é um objeto ou uma classe de dados @Serializable, não uma cadeia de caracteres mágica. Cada funcionalidade define seu próprio tipo de rota no respectivo módulo, mantendo a propriedade do seu contrato de navegação.

// feature/profile/ProfileRoute.kt
import kotlinx.serialization.Serializable

@Serializable
data class ProfileRoute(val userId: String)

As funcionalidades expõem extensões de NavGraphBuilder

O truque principal: cada funcionalidade expõe uma função de extensão de NavGraphBuilder que registra seu destino. A funcionalidade é responsável pela própria tela; o :app apenas chama essa função. A funcionalidade nunca faz referência a outras funcionalidades.

// feature/profile/ProfileNavigation.kt
fun NavGraphBuilder.profileScreen(onBack: () -> Unit) {
    composable<ProfileRoute> { backStackEntry ->
        val route: ProfileRoute = backStackEntry.toRoute()
        ProfileScreen(userId = route.userId, onBack = onBack)
    }
}

Desacoplando com retornos de chamada de navegação

Uma funcionalidade nunca deve chamar navigate(SomeOtherFeatureRoute) diretamente, pois isso exigiria depender da outra funcionalidade. Em vez disso, a funcionalidade expõe retornos de chamada lambda, como onProfileClick. O módulo :app decide para onde eles realmente levam.

// feature/home/HomeNavigation.kt
fun NavGraphBuilder.homeScreen(onProfileClick: (String) -> Unit) {
    composable<HomeRoute> {
        HomeScreen(onUserClick = { userId -> onProfileClick(userId) })
    }
}
// :home does NOT know ProfileRoute exists.

O módulo :app conecta tudo

Apenas o módulo :app conhece todas as rotas e conecta os retornos de chamada à navegação real. Este é o único lugar em que o acoplamento é aceitável — sua função inteira é montar o aplicativo.

// app/AppNavHost.kt
NavHost(navController, startDestination = HomeRoute) {
    homeScreen(
        onProfileClick = { userId ->
            navController.navigate(ProfileRoute(userId)) // app knows both
        }
    )
    profileScreen(onBack = { navController.popBackStack() })
}

Transmitindo argumentos com segurança

Como as rotas são classes de dados @Serializable, os argumentos têm seus tipos verificados no momento da compilação. Você os lê novamente com toRoute() dentro do destino. Chega de analisar cadeias de caracteres ou lidar com falhas em tempo de execução causadas por arguments?.getString(...).

// Reading arguments inside the destination
composable<ProfileRoute> { entry ->
    val args: ProfileRoute = entry.toRoute()
    ProfileScreen(userId = args.userId)
}

// Or directly in a ViewModel via SavedStateHandle
val route: ProfileRoute = savedStateHandle.toRoute()

Compartilhando tipos de rota por meio de um módulo api

Às vezes, uma funcionalidade realmente precisa navegar para outra e quer usar o tipo de rota. Em vez de depender da funcionalidade inteira, exponha apenas a rota em um pequeno módulo :feature:profile:api que contenha somente a rota @Serializable. O módulo pesado :impl permanece privado.

// feature/profile/api  -> only the route type
@Serializable
data class ProfileRoute(val userId: String)

// feature/home/build.gradle.kts
// home may depend on the lightweight api to build the route,
// but never on :feature:profile:impl
implementation(project(":feature:profile:api"))

Navegação aninhada por funcionalidade

Uma funcionalidade com várias telas pode expor um grafo aninhado completo usando navigation<T>. A funcionalidade é responsável pelo próprio fluxo interno; o :app apenas monta o grafo em um único ponto de entrada.

// feature/onboarding/OnboardingNavigation.kt
fun NavGraphBuilder.onboardingGraph(onFinished: () -> Unit) {
    navigation<OnboardingGraph>(startDestination = WelcomeRoute) {
        composable<WelcomeRoute> { WelcomeScreen() }
        composable<PermissionsRoute> { PermissionsScreen(onDone = onFinished) }
    }
}

Links diretos entre módulos

As rotas seguras quanto aos tipos também oferecem suporte a links diretos. Uma funcionalidade declara um padrão de URI de link direto para seu destino; o NavHost do :app encaminha um link recebido para a tela correta da funcionalidade, sem precisar importar outra funcionalidade.

composable<ProfileRoute>(
    deepLinks = listOf(
        navDeepLink<ProfileRoute>(basePath = "https://myapp.com/profile")
    )
) { entry ->
    ProfileScreen(userId = entry.toRoute<ProfileRoute>().userId)
}

Resumo do padrão de desacoplamento

Reunindo tudo, as regras são simples:

  • Cada funcionalidade é responsável pelo seu tipo de rota e por uma extensão de NavGraphBuilder.
  • As funcionalidades comunicam sua intenção por meio de retornos de chamada lambda, não por navegação direta.
  • Apenas o :app conhece todas as funcionalidades e conecta os retornos de chamada às rotas reais.
  • Se uma rota precisar ser compartilhada, exponha-a por meio de um pequeno módulo :api.

Assim, as funcionalidades permanecem independentes, compatíveis com o cache de compilação e livres de ciclos.

Verificação rápida

Em um aplicativo com vários módulos, :feature:home precisa levar o usuário a uma tela em :feature:profile. Qual é a maneira mais organizada de manter as funcionalidades desacopladas?

Recapitulação: navegação entre módulos

Você aprendeu a conectar funcionalidades sem acoplá-las:

  • O único NavHost fica no módulo :app enxuto.
  • Cada funcionalidade é responsável por uma rota @Serializable e por uma extensão de NavGraphBuilder.
  • As funcionalidades expõem retornos de chamada em vez de navegar diretamente para outras funcionalidades.
  • Compartilhe uma rota somente por meio de um pequeno módulo :api quando isso for realmente necessário; links diretos e grafos aninhados seguem o mesmo padrão.

Isso conclui a arquitetura de aplicativos Android com vários módulos: agora você pode dividir, conectar e criar a navegação de uma base de código Android escalável.

Perguntas Frequentes

A aula “Navegação entre módulos” é grátis?

Sim — o texto completo de “Navegação entre módulos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Android Academy, atualize para CoddyKit PRO. O curso de Android Academy inclui 4 aulas no total.

O que vou aprender em “Navegação entre módulos”?

Conecte recursos sem criar acoplamento. Você pratica Android Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Android Academy?

Nenhuma experiência prévia é necessária. Android Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Navegação entre módulos”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Android Academy?

Sim. Cada aula de Android Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que modularizar
  2. Módulos de recursos e núcleo
  3. Gerenciando dependências entre módulos
  4. Navegação entre módulos
← Voltar para Android Academy