Módulos de recursos e núcleo
Defina os limites dos módulos.
Módulos de recursos e núcleo é uma aula grátis de Android Academy no CoddyKit. Esta é a aula 2 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.
Dois tipos de módulos
A maioria dos aplicativos Android modularizados organiza o código em dois tipos principais de módulos: módulos de feature e módulos de core, além de um módulo :app enxuto no topo.
- Módulos de funcionalidades contêm uma parte do aplicativo voltada ao usuário (uma tela ou um fluxo).
- Módulos principais contêm a infraestrutura compartilhada usada por várias funcionalidades.
Nesta lição, você aprenderá a definir bem esses limites.
Anatomia de um módulo de funcionalidades
Um módulo de funcionalidades, como :feature:profile, contém tudo de que uma única funcionalidade precisa: suas telas do Compose, seu ViewModel e seu estado da interface. Ele é vertical: é responsável por toda a parte, desde a interface até o view-model.
Ele depende dos módulos principais para obter elementos compartilhados, mas não deve depender de outros módulos de funcionalidades.
// feature/profile/ProfileScreen.kt
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) {
val state by viewModel.uiState.collectAsStateWithLifecycle()
when (state) {
is ProfileUiState.Loading -> CircularProgressIndicator()
is ProfileUiState.Success -> ProfileContent((state as ProfileUiState.Success).user)
is ProfileUiState.Error -> ErrorMessage()
}
}O ViewModel da funcionalidade
Cada funcionalidade é responsável pelo próprio ViewModel. Ele obtém dados por meio de um repositório de um módulo principal e expõe o estado da interface. O módulo de funcionalidades não sabe como os dados são buscados, apenas conhece o contrato do repositório.
// feature/profile/ProfileViewModel.kt
@HiltViewModel
class ProfileViewModel @Inject constructor(
private val userRepository: UserRepository // from :core:data
) : ViewModel() {
val uiState: StateFlow<ProfileUiState> =
userRepository.observeUser()
.map { ProfileUiState.Success(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), ProfileUiState.Loading)
}Anatomia de um módulo principal
Um módulo principal é horizontal: ele fornece uma capacidade usada em várias funcionalidades. Entre os módulos principais comuns estão:
:core:model— classes de dados simples compartilhadas em todo o aplicativo:core:network— clientes Retrofit/Ktor:core:database— configuração do Room:core:data— repositórios que combinam rede e banco de dados:core:designsystem— tema e componentes reutilizáveis
// core/model/User.kt
data class User(
val id: String,
val name: String,
val avatarUrl: String
)O módulo do sistema de design
:core:designsystem é um dos módulos mais reutilizados. Ele contém seu MaterialTheme, esquemas de cores, tipografia e componentes reutilizáveis, como botões e cartões. Todas as funcionalidades usam a mesma aparência sem copiar código.
// core/designsystem/AppTheme.kt
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) DarkColors else LightColors
MaterialTheme(
colorScheme = colors,
typography = AppTypography,
content = content
)
}O módulo de dados é responsável pelos repositórios
O módulo :core:data expõe interfaces de repositório das quais as funcionalidades dependem, enquanto oculta a implementação. Normalmente, ele depende de :core:network e :core:database, combinando-os em uma única fonte da verdade.
// core/data/UserRepository.kt
interface UserRepository {
fun observeUser(): Flow<User>
suspend fun refresh()
}
// core/data/OfflineFirstUserRepository.kt
internal class OfflineFirstUserRepository @Inject constructor(
private val api: UserApi, // :core:network
private val dao: UserDao // :core:database
) : UserRepository {
override fun observeUser(): Flow<User> = dao.observe().map { it.toUser() }
override suspend fun refresh() { dao.upsert(api.fetch().toEntity()) }
}Mantenha o modelo e o sistema de design leves
Os módulos centrais de nível mais baixo devem depender do mínimo possível. O :core:model idealmente não tem nenhuma dependência do Android — apenas classes de dados simples em Kotlin. Isso permite usá-lo em qualquer lugar e torna a compilação mais rápida.
Se o :core:model começasse a depender do Retrofit ou do Room, todos os módulos que usam suas classes de dados também acabariam incorporando essas bibliotecas pesadas.
// core/model/build.gradle.kts
plugins {
id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classesO módulo :app enxuto
O módulo :app é o montador. Ele deve conter pouquíssima lógica: a classe Application, a única MainActivity, o NavHost de nível superior e a configuração da injeção de dependências. Todas as telas reais ficam nos módulos de funcionalidades.
Um módulo de aplicativo enxuto significa que a maioria das alterações acontece nas funcionalidades, então o módulo :app raramente precisa ser recompilado.
// app/MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme { // from :core:designsystem
AppNavHost() // routes into :feature:* screens
}
}
}
}Definindo bons limites
Como decidir o que deve se tornar um módulo? Algumas heurísticas práticas:
- Uma funcionalidade = uma tela ou um fluxo que o usuário consegue nomear (Início, Perfil, Finalização da compra).
- Um módulo central = uma capacidade reutilizada por 2 ou mais funcionalidades.
- Se duas funcionalidades precisam do mesmo código, mova-o para baixo, para um módulo central.
- Se um módulo faz coisas não relacionadas demais, divida-o.
Opcional: divisão entre api e impl
Às vezes, aplicativos grandes dividem uma funcionalidade em um :feature:profile:api público (interfaces, rotas de navegação) e um :feature:profile:impl privado (telas, modelos de visualização). As outras funcionalidades dependem apenas do pequeno api, nunca da implementação.
Isso é avançado; para a maioria dos aplicativos, um único módulo por funcionalidade é suficiente. Basta saber que esse padrão existe para bases de código muito grandes.
// Other features see only the contract, not the screens
// feature/home depends on :feature:profile:api
interface ProfileEntry {
val route: String
fun NavGraphBuilder.register(navController: NavController)
}Montando o grafo
Veja como as camadas se conectam em nosso exemplo. Observe que as dependências sempre apontam para baixo: app -> feature -> data -> network/database -> model.
// :app -> :feature:home, :feature:profile
// :feature:home -> :core:data, :core:designsystem
// :feature:profile -> :core:data, :core:designsystem
// :core:data -> :core:network, :core:database, :core:model
// :core:network -> :core:model
// :core:database -> :core:model
// :core:model -> (nothing)Verificação rápida
Os módulos :feature:home e :feature:profile precisam buscar e armazenar em cache os dados do usuário. Onde o código do repositório deve ficar?
Recapitulação: módulos de funcionalidades e centrais
Você aprendeu a dividir o código em duas camadas:
- Módulos de funcionalidades são fatias verticais (tela + ViewModel + estado da interface).
- Módulos centrais são capacidades horizontais (modelo, rede, banco de dados, dados, sistema de design).
- O módulo
:apppermanece enxuto e apenas monta as funcionalidades. - O código compartilhado é movido para baixo, para o núcleo; o
:core:modelpermanece independente do Android e leve.
A seguir, você gerenciará as dependências entre esses módulos e manterá o grafo organizado.
Perguntas Frequentes
A aula “Módulos de recursos e núcleo” é grátis?
Sim — o texto completo de “Módulos de recursos e núcleo” é 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 “Módulos de recursos e núcleo”?
Defina os limites dos módulos. 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 2 de 4.
Quanto tempo leva a aula “Módulos de recursos e núcleo”?
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
- Por que modularizar
- Módulos de recursos e núcleo
- Gerenciando dependências entre módulos
- Navegação entre módulos