RxJava é uma biblioteca de programação reativa para a JVM que implementa fluxos de dados assíncronos através do padrão Observable com operadores funcionais de transformação. Ela porta os conceitos do ReactiveX para Java e Kotlin, fornecendo uma API unificada para trabalhar com requisições de rede, bancos de dados, eventos de UI e tarefas em segundo plano. De acordo com ReactiveX, 2025, a biblioteca é usada em mais de 120.000 projetos no GitHub e é o padrão de programação reativa para Android até a chegada do Kotlin Flow. RxJava substitui AsyncTask, Loader e callbacks por uma única cadeia de processamento de dados.
Pontos principais
RxJava é uma implementação da biblioteca ReactiveX (Reactive Extensions) para a Máquina Virtual Java. A primeira versão do RxJava foi lançada pela Netflix em 2013 para gerenciar chamadas assíncronas em aplicações do lado do servidor. Na época de sua criação, as principais alternativas em Java eram Future e Callback — ambas as abordagens levavam ao callback-hell e ao gerenciamento complexo de threads. RxJava introduziu a composição de operações assíncronas através do Observable com cadeias de operadores funcionais.
A arquitetura do RxJava é baseada na especificação Reactive Streams — um padrão para processamento assíncrono de fluxos com contrapressão não bloqueante. A especificação define quatro interfaces: Publisher, Subscriber, Subscription e Processor. RxJava 2+ implementa completamente Reactive Streams através do tipo Flowable, cumprindo os contratos de contrapressão ao contrário do RxJava 1. Observable no RxJava 2 não suporta contrapressão — é destinado a fluxos com um pequeno número de eventos ou eventos de UI.
De acordo com a pesquisa JetBrains, 2025, RxJava está entre as 3 principais bibliotecas para desenvolvimento Android. Os principais casos de uso incluem: manipulação de requisições de rede via Retrofit (integrado com RxJava através do CallAdapter), trabalho com Room (consultas reativas retornam Flowable ou Maybe), animações e eventos de UI via RxBinding, e busca com debounce na entrada de texto. Todos esses cenários compartilham um padrão de cadeia comum: fonte (Observable) → transformação (operadores) → subscrição (subscribe).
RxJava 1 (2013) estabeleceu a base com Observable e operadores, mas sofria de problemas de contrapressão — em fluxos rápidos, os dados se acumulavam na memória, causando OutOfMemoryError. RxJava 2 (2016) corrigiu a arquitetura separando Observable (sem contrapressão) e Flowable (com contrapressão). RxJava 3 (2020) adicionou suporte ao Java 8 Stream API, operadores adicionais e desempenho de subscrição melhorado. Atualmente, RxJava 3 é a versão recomendada para novos projetos.
RxJava fornece cinco tipos principais de fontes reativas, cada uma projetada para um cenário específico. Observable e Flowable emitem múltiplos valores, Single emite um valor ou erro, Completable emite apenas a conclusão sem dados, e Maybe emite um valor, zero ou erro. Escolher o tipo correto reduz o volume de código e torna a cadeia autodocumentada.
| Tipo | Número de eventos | Contrapressão | Cenário |
|---|---|---|---|
| Observable | 0..N, depois conclusão | Não | Eventos de UI, fluxos curtos |
| Flowable | 0..N, depois conclusão | Sim | Respostas de rede, fluxos de BD |
| Single | Exatamente 1 ou erro | Não | Requisição HTTP, leitura de um registro |
| Completable | 0 (apenas conclusão) | Não | Escrita em BD, envio de evento |
| Maybe | 0, 1 ou erro | Não | Cache: valor existe ou não |
Flowable é o tipo mais flexível para trabalhar com grandes fluxos de dados. Ele implementa o Publisher do Reactive Streams com suporte a contrapressão: o consumidor pode solicitar um número específico de elementos via Subscription.request(n). Isso evita o transbordamento do buffer quando as velocidades do produtor e consumidor não coincidem. Se a contrapressão não for crítica, use Observable — ele tem menos sobrecarga devido à ausência do mecanismo de request.
Single é a escolha ideal para requisições HTTP. Retrofit 2 com RxJava CallAdapter retorna Single<ResponseBody> para cada requisição. Single garante exatamente uma chamada para onSuccess ou onError, correspondendo à semântica de uma requisição HTTP — uma resposta ou um erro. Completable é usado para operações de escrita que não retornam dados: insert, update, delete. Maybe é conveniente para verificação de cache — pode retornar um valor ou não.
// Exemplo de uso do Single para uma requisição HTTP
interface ApiService {
@GET("users/{id}")
fun getUser(@Path("id") userId: Int): Single<User>
}
// Subscrição com processamento na thread principal
apiService.getUser(42)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
textView.text = user.name
}, { error ->
Log.e("API", "Error: ${error.message}")
})
.addTo(compositeDisposable)
Operadores no RxJava são funções de alta ordem que recebem uma fonte reativa e retornam outra, transformando o fluxo de dados. RxJava 3 contém mais de 400 operadores, divididos em categorias: transformação, filtragem, combinação, tratamento de erros e gerenciamento de tempo. Cada operador é preguiçoso — a cadeia é construída na declaração e executada na subscrição.
map é o operador básico que transforma cada valor através de uma função. flatMap recebe uma função que retorna um Observable para cada elemento e achata o resultado em um único fluxo. switchMap é semelhante ao flatMap, mas quando um novo elemento chega, ele cancela a subscrição do Observable anterior. concatMap preserva a ordem dos elementos — ao contrário do flatMap, ele subscreve sequencialmente a cada Observable aninhado.
// Análise JSON com transformação e filtragem
apiService.getUsers()
.flatMap { users ->
Observable.fromIterable(users)
}
.filter { user ->
user.age >= 18
}
.map { user ->
UserDto(user.name, user.age)
}
.toList()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ adapter.submitList(it) },
{ Log.e("Erro", it.message) })
Combinação de fluxos é uma área onde RxJava se destaca particularmente. zip combina elementos de múltiplos Observables aos pares por índice: primeiro com primeiro, segundo com segundo. combineLatest emite um novo valor quando qualquer fluxo muda, combinando os valores mais recentes de todos os fluxos. merge combina múltiplos Observables em um, preservando a ordem de chegada dos eventos. concat subscreve sequencialmente a cada Observable e passa todos os seus eventos antes de passar ao próximo.
Gerenciamento de tempo inclui debounce (aguardar uma pausa no fluxo antes de emitir), throttleFirst (emitir o primeiro evento, ignorar os restantes dentro de uma janela), timeout (erro se nenhum evento chegar dentro do intervalo). A busca com debounce na entrada de texto é o cenário mais comum: searchObservable.debounce(300, MILLISECONDS).distinctUntilChanged() evita requisições desnecessárias durante digitação rápida.
| Categoria | Operador | Comportamento |
|---|---|---|
| Transformação | map / flatMap / switchMap | Transformar um valor ou fluxo |
| Filtragem | filter / distinct / take | Selecionar valores por condição |
| Combinação | zip / combineLatest / merge | Combinar 2+ fluxos |
| Erros | onErrorResumeNext / retry | Recuperar de falhas |
| Utilitários | delay / timeout / debounce | Gerenciamento de tempo em fluxos |
Scheduler no RxJava é uma abstração sobre um pool de threads. A biblioteca fornece cinco Schedulers integrados: Schedulers.io() para operações de E/S (rede, arquivos), Schedulers.computation() para tarefas intensivas de CPU, Schedulers.newThread() para uma nova thread cada vez, Schedulers.single() para execução em thread única e Schedulers.trampoline() para execução imediata na thread atual.
subscribeOn determina em qual Scheduler o Observable fonte é executado. Se houver vários subscribeOn na cadeia, a prioridade é do mais próximo da fonte. observeOn muda o downstream para o Scheduler especificado — cada uso de observeOn altera a thread para os operadores subsequentes. Um padrão típico Android: subscribeOn(Schedulers.io()) para operações de rede, observeOn(AndroidSchedulers.mainThread()) para atualizações de UI.
// Processamento multithread com troca de contexto
Observable.fromCallable(() -> database.getItems())
.subscribeOn(Schedulers.io()) // BD no io
.map(items -> processItems(items)) // transformação no io
.observeOn(Schedulers.computation()) // mudar para computation
.map(processed -> compressImages(processed))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> ui.showResult(result))
AndroidSchedulers.mainThread() é um Scheduler da biblioteca RxAndroid que executa código na thread principal do Android. É obrigatório para qualquer atualização de UI em uma cadeia reativa. A biblioteca usa Handler internamente e garante execução na thread de UI mesmo sob alta carga. Para operações em segundo plano, Schedulers.io() suporta um pool de threads ilimitado e é adequado para qualquer operação bloqueante. Schedulers.computation() usa um pool fixo igual ao número de núcleos de CPU.
RxJava no Android é usado para três cenários principais: consultas reativas ao Room, integração com Retrofit e vinculação reativa de UI via RxBinding. Cada cenário tem seu próprio conjunto de tipos: Room retorna Flowable para consultas observáveis, Retrofit retorna Single para requisições HTTP, RxBinding retorna Observable para eventos de UI.
Room é uma biblioteca de persistência de dados do Google. A partir do Room 2.1, o banco de dados suporta tipos de retorno reativos: Flowable e Observable. Quando qualquer registro na tabela muda, o Room envia automaticamente um novo valor para o fluxo. O desenvolvedor subscreve ao Flowable no ViewModel e recebe dados atualizados sem consultas manuais a cada alteração.
// Room DAO com consulta reativa
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
fun getUserById(@Param("id") userId: Int): Flowable<User>
@Insert
fun insertUser(user: User): Completable
}
// ViewModel — composição Room + Network
class UserViewModel(private val dao: UserDao) : ViewModel() {
val users: Flowable<List<User>> = dao.getAllUsers()
.subscribeOn(Schedulers.io())
}
O padrão MVVM + RxJava é construído sobre o ViewModel não ter referências à View. O ViewModel publica fontes reativas (Flowable, LiveData via Transformations), e a Activity ou Fragment subscreve a elas. Isso proporciona testabilidade: o ViewModel é testado sem a UI, substituindo Schedulers via RxJavaPlugins.setComputationScheduler. CompositeDisposable no ViewModel gerencia o ciclo de vida das subscrições — ao onCleared(), todas as subscrições são canceladas.
Kotlin Flow é uma implementação nativa de fluxos frios em Kotlin, incorporada às corrotinas e apresentada no Kotlin 1.3. Flow resolve os mesmos problemas que o RxJava, mas com diferenças fundamentais: suporte nativo a corrotinas (funções suspend), cancelamento via coroutine cancellation e ausência de problemas de contrapressão — Flow usa suspend em vez de buffer. Flow faz parte da biblioteca padrão do Kotlin, não exigindo dependências adicionais.
RxJava continua sendo a escolha preferida para projetos Java, projetos com suporte a Java 7-8 e bases de código existentes em RxJava. O ecossistema do RxJava é significativamente mais rico: mais de 400 operadores contra cerca de 50 no Flow, integração com Retrofit via CallAdapter nativo, suporte a contrapressão via Flowable, e RxBinding, RxPermissions, RxLocation para Android. Kotlin Flow está alcançando rapidamente, mas a flexibilidade do RxJava em cenários complexos de combinação de fluxos ainda é superior.
| Característica | RxJava | Kotlin Flow |
|---|---|---|
| Idioma | Java / Kotlin | Kotlin apenas |
| Cancelamento | Disposable / CompositeDisposable | Coroutine cancellation |
| Contrapressão | Flowable (estratégias BUFFER, DROP, LATEST) | Via conflate / buffer |
| Operadores | 400+ | ~50 (extensível) |
| Integração com Room | Flowable, Observable | Flow, StateFlow |
| ViewModel | CompositeDisposable | viewModelScope + Flow |
Perguntas frequentes
Observable não suporta contrapressão — se o produtor for mais rápido que o consumidor, os eventos se acumulam na memória. Flowable implementa Reactive Streams com contrapressão via Subscription.request(), evitando o transbordamento do buffer quando as velocidades não coincidem.
Single é usado para operações que retornam exatamente um valor ou erro: requisições HTTP, leitura de um único registro do BD, cálculo de um resultado. Single corresponde semanticamente ao Future e reduz o código eliminando onComplete não utilizado.
O método dispose() no Disposable cancela uma subscrição. Para gerenciamento em grupo, usa-se CompositeDisposable — ele coleta todos os Disposables e os descarta simultaneamente ao chamar clear(). O local típico é onCleared() no ViewModel ou onPause() na Activity.
flatMap subscreve a todos os Observables aninhados e combina seus eventos em ordem arbitrária. switchMap quando um novo elemento chega, cancela a subscrição do Observable anterior e subscreve ao novo. switchMap é usado em buscas — cada nova requisição cancela a anterior.
Para novos projetos em Kotlin, Flow é preferível devido à integração com corrotinas e menor tamanho. Para projetos existentes em RxJava, a migração só se justifica se toda a base de código estiver migrando para corrotinas — o uso intermediário de ambas as bibliotecas complica a arquitetura.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também