O que é Composable em Kotlin?
Uma função Composable é uma função anotada com @Composable que descreve parte da interface do usuário no Jetpack Compose, o toolkit moderno de UI declarativa do Android. Em vez de montar telas com XML e manipular Views programaticamente, você escreve funções Kotlin que descrevem como a UI deve parecer para um dado estado.
O Compose e inspirado em frameworks como React e Flutter, mas aproveita todo o poder do Kotlin: type safety, extension functions, coroutines é uma sintaxe concisa que faz a construcao de interfaces parecer natural.
Sintaxe básica
import androidx.compose.runtime.Composable
import androidx.compose.material3.Text
@Composable
fun Saudacao(nome: String) {
Text(text = "Ola, $nome!")
}
A anotacao @Composable informa ao compilador do Compose que essa função descreve UI e pode ser recomposta (re-executada) quando os dados mudam. Funções Composable só podem ser chamadas dentro de outros contextos Composable.
Composição de funções
O poder do Compose esta na composição. Você cria componentes pequenos e os combina para formar telas completas:
@Composable
fun CartaoDeUsuario(nome: String, email: String) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = nome,
style = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = email,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@Composable
fun ListaDeUsuarios(usuarios: List<Usuario>) {
LazyColumn {
items(usuarios) { usuario ->
CartaoDeUsuario(
nome = usuario.nome,
email = usuario.email
)
}
}
}
Cada função Composable e um bloco reutilizavel. CartaoDeUsuario não sabe onde sera usado, e ListaDeUsuarios não sabe como o cartao e renderizado internamente. Essa separação torna o código modular e testavel.
Estado em Composables
Funções Composable são reexecutadas quando o estado muda. Para gerenciar estado local, use remember e mutableStateOf:
@Composable
fun Contador() {
var contagem by remember { mutableStateOf(0) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Contagem: $contagem")
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { contagem++ }) {
Text("Incrementar")
}
}
}
Quando contagem muda, o Compose recompoe apenas as partes da UI que dependem desse valor. Isso e feito de forma inteligente pelo runtime do Compose, que rastreia quais Composables leem quais estados.
Recomposicao
Recomposicao e o processo pelo qual o Compose reexecuta funções Composable quando os dados de entrada mudam. E importante entender que:
- A recomposicao pode acontecer a qualquer momento e em qualquer ordem.
- Funções Composable devem ser idempotentes: chamar com os mesmos parametros deve produzir o mesmo resultado.
- Funções Composable não devem ter efeitos colaterais não controlados.
// Correto: sem efeitos colaterais
@Composable
fun ExibirNome(nome: String) {
Text(text = nome)
}
// Incorreto: efeito colateral na recomposicao
@Composable
fun ExibirNomeComLog(nome: String) {
println("Recompondo...") // Pode ser chamado muitas vezes!
Text(text = nome)
}
Para efeitos colaterais controlados, use APIs como LaunchedEffect, SideEffect e DisposableEffect.
Efeitos colaterais controlados
@Composable
fun TelaDeDetalhes(userId: String) {
var usuario by remember { mutableStateOf<Usuario?>(null) }
LaunchedEffect(userId) {
// Executa quando userId muda
usuario = repositorio.buscarUsuario(userId)
}
usuario?.let { u ->
Column {
Text(text = u.nome)
Text(text = u.email)
}
}
}
LaunchedEffect lanca uma coroutine que e cancelada e reiniciada quando a chave (userId) muda. Isso garante que efeitos colaterais sejam gerenciados corretamente no ciclo de vida do Composable.
Modifiers
Modifiers são o mecanismo do Compose para decorar e configurar componentes:
@Composable
fun CartaoEstilizado() {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable { /* acao */ }
) {
Text(
text = "Conteudo do cartao",
modifier = Modifier.padding(24.dp)
)
}
}
A ordem dos modifiers importa: padding antes de clickable produz resultado diferente de clickable antes de padding.
Quando usar Composables
Composables são usados em qualquer projeto Android que adote Jetpack Compose:
- Telas de aplicativos: construir layouts completos de forma declarativa.
- Componentes reutilizaveis: criar uma biblioteca de componentes de UI consistentes.
- Previews: usar
@Previewpara visualizar componentes no Android Studio sem rodar o app. - Testes de UI: Composables são facilmente testáveis com a biblioteca de testes do Compose.
- Compose Multiplatform: o mesmo conceito funciona em desktop, web e iOS com Kotlin Multiplatform.
Casos de Uso no Mundo Real
Design systems corporativos: empresas criam bibliotecas de Composables reutilizaveis (botoes, campos de texto, cartoes, modais) que encapsulam regras de design e acessibilidade. Equipes de produto consomem esses componentes para garantir consistencia visual em dezenas de telas sem duplicar código de estilizacao.
Telas de formularios dinâmicos: aplicações que renderizam formularios baseados em configuracoes do servidor (como cadastros, pesquisas ou checklists) usam Composables parametrizados que recebem a definicao dos campos e geram a interface automaticamente. Cada tipo de campo (texto, selecao, data) e um Composable independente composto pela tela pai.
Dashboards com gráficos e metricas: aplicações de analytics e monitoramento constroem paineis interativos usando Composables que reagem a mudancas de estado em tempo real. Graficos, indicadores e tabelas sao componentes Compose que se recompoem automaticamente quando os dados sao atualizados via Flow ou StateFlow do ViewModel.
aplicações multiplataforma com Compose Multiplatform: projetos que compartilham a mesma base de código Kotlin entre Android, desktop (Windows, macOS, Linux) e iOS usam Composables como a camada de UI unificada. Um mesmo componente de lista ou navegação funciona em todas as plataformas com adaptacoes minimas.
Boas Praticas
- Aplique state hoisting por padrão: Composables devem receber o estado como parametro e emitir eventos via callbacks. Isso torna o componente stateless, reutilizavel e facilmente testavel com a biblioteca de testes do Compose.
- Mantenha Composables pequenos e focados em uma única responsabilidade. Um Composable que faz muita coisa (busca dados, processa lógica e renderiza UI) e difícil de testar e reutilizar. Delegue lógica de negócio ao ViewModel.
- Use
@Previewcom múltiplas configuracoes (temas claro e escuro, diferentes tamanhos de tela, dados de exemplo variados) para validar a aparencia do componente sem precisar compilar e executar o aplicativo inteiro. - Evite efeitos colaterais diretos dentro de Composables. Use
LaunchedEffectpara coroutines,SideEffectpara código sincrono que precisa executar apos a composicao eDisposableEffectpara recursos que precisam de limpeza. - Preste atencao na ordem dos Modifiers: cada modifier e aplicado em sequência e afeta o resultado visual de forma cumulativa. Por exemplo,
paddingantes debackgroundadiciona espaco dentro da area colorida, enquanto a ordem inversa adiciona espaco fora.
Perguntas Frequentes
P: Qual a diferenca entre remember e rememberSaveable no Compose?
R: remember preserva o estado entre recomposicoes, mas o valor se perde em mudancas de configuração (como rotação de tela) ou quando o processo e destruído. rememberSaveable salva o estado automaticamente no SavedStateHandle, sobrevivendo a mudancas de configuração e até a morte do processo, desde que o valor seja serializavel.
P: Composables podem ser usados fora do Android? R: Sim. Com o Compose Multiplatform da JetBrains, você pode usar Composables em aplicações desktop (JVM), web (via Kotlin/Wasm) e iOS. A API de composicao e recomposicao e a mesma; o que muda sao os componentes de plataforma subjacentes que renderizam os elementos visuais.
P: Como testar Composables de forma automatizada?
R: Use a biblioteca compose-ui-test que fornece a ComposeTestRule. Com ela você pode renderizar Composables isolados, interagir com elementos via onNodeWithText e performClick, e verificar estados com assertivas como assertIsDisplayed. Testes de Composable executam no JVM sem precisar de um emulador.
P: Por que meu Composable esta recompondo mais vezes do que o esperado?
R: Recomposicoes excessivas geralmente acontecem quando o estado e lido em um escopo mais amplo do que necessário, quando lambdas sao recriadas a cada recomposicao (use remember para estabiliza-las), ou quando objetos de dados não implementam equals corretamente. Use o Layout Inspector do Android Studio para identificar quais Composables estao recompondo e com que frequência.
Erros comuns
Colocar lógica de negócio dentro do Composable: Composables devem apenas descrever UI. Logica de negócio pertence ao ViewModel ou a camadas inferiores.
Esquecer
remember: semremember, o estado e recriado a cada recomposicao, perdendo o valor anterior.
// Errado: contagem volta a 0 a cada recomposicao
@Composable
fun ContadorQuebrado() {
var contagem = mutableStateOf(0) // Falta remember!
// ...
}
Efeitos colaterais descontrolados: fazer chamadas de rede, acessar banco de dados ou modificar estado global diretamente dentro de um Composable sem usar
LaunchedEffectou similar.Nao elevar o estado (state hoisting): manter estado em componentes filhos quando ele deveria ser controlado pelo pai. Isso dificulta reutilização e testes.
Ignorar a ordem dos Modifiers: como modifiers são aplicados em cadeia, a ordem afeta o resultado visual. Testar e visualizar com
@Previewajuda a pegar esses problemas cedo.
State hoisting
Um padrão fundamental em Compose e elevar o estado para o componente pai:
// Componente stateless (sem estado proprio)
@Composable
fun CampoDeTexto(
valor: String,
onValorMudou: (String) -> Unit
) {
TextField(
value = valor,
onValueChange = onValorMudou
)
}
// Componente pai controla o estado
@Composable
fun Formulario() {
var nome by remember { mutableStateOf("") }
CampoDeTexto(
valor = nome,
onValorMudou = { nome = it }
)
}
Isso torna CampoDeTexto reutilizavel e testavel, pois ele não gerencia seu próprio estado.
Termos relacionados
- State: o mecanismo de estado reativo que aciona recomposicoes quando valores mudam.
- Modifier: objeto que configura aparencia e comportamento de componentes Compose.
- ViewModel: gerencia estado e lógica de negócio fora da camada de UI.
- LaunchedEffect: API para executar efeitos colaterais controlados dentro de Composables.
- Recomposicao: processo de reexecucao de funções Composable quando seus inputs mudam.
- remember: função que preserva estado entre recomposicoes.
Composables representam uma mudanca de paradigma na construcao de interfaces em Kotlin. Ao tratar a UI como função do estado, o Compose elimina toda uma classe de bugs relacionados a sincronizacao entre dados e interface, tornando o desenvolvimento mais previsivel e produtivo.