Kotlin Coroutines vs RxJava: programacao assincrona em 2026
A programacao assincrona e essencial no desenvolvimento moderno, seja para chamadas de rede, operacoes de banco de dados ou processamento em background. Durante anos, RxJava foi a solucao dominante no ecossistema Android e JVM. Com a maturidade de Kotlin Coroutines e Flow, muitas equipes migraram ou consideram migrar. Este artigo compara as duas abordagens em profundidade.
Visao geral
| Caracteristica | Kotlin Coroutines | RxJava |
|---|---|---|
| Linguagem | Kotlin nativo | Java (com extensoes Kotlin) |
| Paradigma | Suspensao sequencial | Streams reativos |
| Curva de aprendizado | Moderada | Alta |
| Backpressure | Flow (nativo) | Flowable (explicito) |
| Integracao Android | Oficial (Jetpack) | Biblioteca terceira |
| Peso da dependencia | Leve (~1.5MB) | Pesado (~3MB+) |
| Suporte multiplatform | Sim | Apenas JVM |
| Cancellamento | Estruturado (scope) | Manual (Disposable) |
Modelo de programacao
A diferenca fundamental esta na forma como cada abordagem expressa operacoes assincronas.
Coroutines: codigo sequencial com suspensao
Coroutines permitem escrever codigo assincrono que parece sincrono. A palavra-chave suspend marca funcoes que podem pausar sem bloquear a thread:
// Coroutines: leitura natural, de cima para baixo
suspend fun buscarPerfilCompleto(userId: Int): PerfilCompleto {
val usuario = api.buscarUsuario(userId) // suspende
val posts = api.buscarPosts(userId) // suspende
val seguidores = api.buscarSeguidores(userId) // suspende
return PerfilCompleto(usuario, posts, seguidores)
}
// Execucao paralela quando necessario
suspend fun buscarPerfilParalelo(userId: Int): PerfilCompleto = coroutineScope {
val usuario = async { api.buscarUsuario(userId) }
val posts = async { api.buscarPosts(userId) }
val seguidores = async { api.buscarSeguidores(userId) }
PerfilCompleto(usuario.await(), posts.await(), seguidores.await())
}
RxJava: cadeias de operadores reativos
RxJava modela tudo como streams de dados transformados por operadores:
// RxJava: cadeia de operadores
fun buscarPerfilCompleto(userId: Int): Single<PerfilCompleto> {
return Single.zip(
api.buscarUsuario(userId),
api.buscarPosts(userId),
api.buscarSeguidores(userId)
) { usuario, posts, seguidores ->
PerfilCompleto(usuario, posts, seguidores)
}
}
// Sequencial em RxJava
fun buscarPerfilSequencial(userId: Int): Single<PerfilCompleto> {
return api.buscarUsuario(userId)
.flatMap { usuario ->
api.buscarPosts(userId).map { posts -> usuario to posts }
}
.flatMap { (usuario, posts) ->
api.buscarSeguidores(userId).map { seguidores ->
PerfilCompleto(usuario, posts, seguidores)
}
}
}
A versao com Coroutines e significativamente mais legivel. A versao RxJava requer conhecimento de operadores como zip, flatMap e map para expressar a mesma logica.
Tratamento de erros
Coroutines: try/catch padrao
suspend fun carregarDados(): Resultado {
return try {
val dados = api.buscar()
Resultado.Sucesso(dados)
} catch (e: HttpException) {
Resultado.Erro("Erro HTTP: ${e.code()}")
} catch (e: IOException) {
Resultado.Erro("Sem conexao")
}
}
RxJava: operadores de erro
fun carregarDados(): Single<Resultado> {
return api.buscar()
.map<Resultado> { dados -> Resultado.Sucesso(dados) }
.onErrorReturn { e ->
when (e) {
is HttpException -> Resultado.Erro("Erro HTTP: ${e.code()}")
is IOException -> Resultado.Erro("Sem conexao")
else -> Resultado.Erro("Erro desconhecido")
}
}
}
O try/catch de Coroutines e familiar para qualquer desenvolvedor. Em RxJava, voce precisa conhecer onErrorReturn, onErrorResumeNext, retry e outros operadores especificos para tratamento de erros.
Cancelamento
Coroutines: cancelamento estruturado
class MinhaViewModel : ViewModel() {
// viewModelScope cancela automaticamente quando ViewModel e destruido
fun carregarDados() {
viewModelScope.launch {
val dados = repositorio.buscar() // cancelado automaticamente
_estado.value = dados
}
}
}
// Cancelamento manual
val job = scope.launch {
while (isActive) {
val dado = canal.receive()
processar(dado)
}
}
job.cancel() // cancela limpo
RxJava: Disposable manual
class MinhaViewModel : ViewModel() {
private val disposables = CompositeDisposable()
fun carregarDados() {
disposables.add(
repositorio.buscar()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ dados -> _estado.value = dados },
{ erro -> _estado.value = Estado.Erro(erro) }
)
)
}
override fun onCleared() {
disposables.clear() // esqueceu? vazamento de memoria
}
}
O cancelamento estruturado de Coroutines e uma vantagem significativa. Com viewModelScope, lifecycleScope e coroutineScope, o cancelamento e automatico e hierarquico. Em RxJava, esquecer de chamar dispose() e uma fonte comum de bugs e vazamentos.
Fluxos de dados reativos
Kotlin Flow vs Observable/Flowable
// Kotlin Flow
fun observarUsuarios(): Flow<List<Usuario>> = flow {
while (true) {
val usuarios = api.buscarUsuarios()
emit(usuarios)
delay(30_000) // atualiza a cada 30 segundos
}
}.catch { e ->
emit(emptyList())
}.flowOn(Dispatchers.IO)
// Consumo
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.usuarios.collect { lista ->
adapter.submitList(lista)
}
}
}
// RxJava Observable
fun observarUsuarios(): Observable<List<Usuario>> {
return Observable.interval(0, 30, TimeUnit.SECONDS)
.flatMapSingle { api.buscarUsuarios() }
.onErrorReturnItem(emptyList())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
// Consumo
disposables.add(
viewModel.observarUsuarios()
.subscribe { lista -> adapter.submitList(lista) }
)
StateFlow vs BehaviorSubject
// Kotlin StateFlow
class ContadorViewModel : ViewModel() {
private val _contador = MutableStateFlow(0)
val contador: StateFlow<Int> = _contador.asStateFlow()
fun incrementar() { _contador.value++ }
}
// RxJava BehaviorSubject
class ContadorViewModel : ViewModel() {
private val _contador = BehaviorSubject.createDefault(0)
val contador: Observable<Int> = _contador.hide()
fun incrementar() { _contador.onNext(_contador.value!! + 1) }
}
Performance
Em benchmarks praticos, Coroutines geralmente apresentam menor uso de memoria e latencia comparable ou inferior a RxJava para a maioria dos cenarios. A principal razao e que coroutines suspensas nao alocam objetos intermediarios na mesma proporcao que cadeias de operadores RxJava.
| Metrica | Coroutines | RxJava |
|---|---|---|
| Memoria por operacao | Baixa (state machine) | Moderada (objetos Observable) |
| Overhead de criacao | Minimo | Moderado (cadeia de operadores) |
| Troca de contexto | Eficiente (Dispatchers) | Schedulers (thread pool) |
| Cold start | Rapido | Mais lento (setup da cadeia) |
Para cenarios com milhares de operacoes concorrentes, coroutines escalam melhor porque cada coroutine ocupa poucos bytes na memoria, enquanto cada subscription RxJava mantem uma cadeia de objetos.
Quando usar cada um
Escolha Kotlin Coroutines quando:
- Voce inicia um projeto novo em Kotlin
- Precisa de integracao nativa com Jetpack (ViewModel, Room, Compose)
- Quer codigo mais legivel e facil de depurar
- Precisa de suporte Kotlin Multiplatform
- A equipe tem experiencia limitada com programacao reativa
- Cancelamento automatico e importante
Escolha RxJava quando:
- O projeto existente ja usa RxJava extensivamente
- Voce precisa de operadores complexos de combinacao de streams que nao tem equivalente direto em Flow
- A equipe ja domina o modelo reativo
- Voce trabalha com um codebase Java que nao pode migrar para Kotlin
Migracao gradual
Ambas as abordagens podem coexistir. A biblioteca kotlinx-coroutines-rx3 oferece funcoes de conversao:
// RxJava para Flow
val flow: Flow<String> = observable.asFlow()
// Flow para Observable
val observable: Observable<String> = flow.asObservable()
// Single para suspend
val resultado: String = single.await()
Veredito
Em 2026, Kotlin Coroutines com Flow e a escolha recomendada para novos projetos Kotlin. A integracao com o ecossistema Android Jetpack e nativa, o modelo de cancelamento estruturado previne vazamentos, e o codigo resultante e mais legivel. RxJava permanece uma opcao valida para projetos existentes que ja investiram no modelo reativo, mas a tendencia clara do ecossistema e em direcao a Coroutines. Se voce esta comecando hoje, invista seu tempo em dominar Coroutines e Flow.