RxJava는 Observable과 Observer를 통해 Observer 패턴을 구현하는 Java 및 Android용 리액티브 프로그래밍 라이브러리입니다. ReactiveX GitHub, 2026에 따르면, RxJava는 연산자 체인을 사용하여 비동기 데이터 스트림과 이벤트를 처리할 수 있습니다. 기본 단위는 Observable이며, 변환 체인을 통해 Observer에 데이터를 발행합니다. RxJava 3은 Java 8 람다, Reactive Streams 및 RxAndroid를 통한 Android 통합을 지원하는 현재 안정 버전입니다.
핵심 사항
RxJava는 ReactiveX 사양의 Java 구현으로, 관찰 가능한 스트림(Observable)을 사용한 비동기 프로그래밍을 위한 라이브러리입니다. RxJava 2는 2016년에 Reactive Streams(Flowable) 지원과 rx.Observable 및 io.reactivex.Observable로의 분할과 함께 출시되었습니다. RxJava 3(2019)는 RxJava 2와의 하위 호환성을 가진 현재 주요 버전입니다.
RxJava의 핵심 아이디어는 모든 것이 스트림이라는 것입니다: 데이터 스트림, 이벤트 스트림, 상태 스트림. 모든 비동기 작업은 데이터, 오류 또는 완료 신호를 발행하는 Observable로 표현할 수 있습니다. Observer가 Observable을 구독하고 실시간으로 알림을 받습니다.
Badoo(2024)에 따르면, 코루틴으로 전환하기 전에 Google Play 상위 200개 Android 앱 중 76%가 비동기 작업에 RxJava를 사용했습니다. 현재는 코루틴에 비중을 빼앗기고 있지만, RxJava는 수천 개 앱의 프로덕션 코드에 남아 있으며 성숙하고 검증된 기술로 간주됩니다. ReactiveX는 크로스 플랫폼 사양으로 JavaScript(RxJS), .NET(Rx.NET), Swift(RxSwift) 등에서도 구현되었습니다.
ReactiveX는 두 가지 메커니즘으로 고전적인 Observer 패턴을 확장합니다: 연산자 체이닝과 Scheduler 기반 스레딩. Observable은 Observer가 구독할 때까지 데이터 발행을 시작하지 않습니다(지연 평가). 이를 통해 구독이 있을 때만 활성화되는 데이터 파이프라인을 구축할 수 있습니다.
Observable — onError 또는 onComplete와 함께 0..N개 요소를 발행하는 기본 유형. 무제한 데이터 스트림에 적합합니다. 예를 들어, 클릭 이벤트 또는 위치 업데이트 등이 있습니다. Observable은 배압을 지원하지 않습니다.
Flowable — 배압을 지원하는 Observable의 Reactive Streams 버전. 데이터 소스가 Observer의 처리 속도보다 빠르게 요소를 생성할 수 있을 때 사용합니다. Flowable은 BACKPRESSURE_BUFFER, DROP, LATEST 및 ERROR 전략을 지원합니다.
| 유형 | 요소 | 배압 | 용도 |
|---|---|---|---|
| Observable | 0..N | 없음 | UI 이벤트, 소규모 스트림 |
| Flowable | 0..N | 있음 | 대용량 데이터, 실시간 |
| Single | 1 (onSuccess/onError) | — | 단일 응답(네트워크) |
| Maybe | 0..1 | — | 선택적 값(캐시) |
| Completable | 0 (onComplete/onError) | 데이터 없는 작업(쓰기) |
Single은 정확히 하나의 요소 또는 오류를 발행합니다 — 네트워크 요청에 이상적입니다. Maybe는 0 또는 1개의 요소를 발행하며, 데이터가 없을 수 있는 캐시에 적합합니다. Completable은 데이터 없이 onComplete 또는 onError만 발행하며, 쓰기 또는 삭제 작업에 편리합니다. 이러한 유형은 계약을 특정 경우로 제한하여 API를 단순화합니다. Retrofit(Android용 인기 HTTP 클라이언트)은 다섯 가지 RxJava 유형을 모두 직접 지원하므로 추가 코드 없이 각 엔드포인트에 가장 적합한 반환 유형을 선택할 수 있습니다.
연산자는 하나의 Observable을 다른 Observable로 변환하는 함수입니다. 연산자 체인은 데이터 파이프라인을 설명합니다: 각 연산자는 이전 연산자에서 스트림을 받아 변환한 후 다음으로 전달합니다. RxJava에는 범주별로 분류된 200개 이상의 연산자가 포함되어 있습니다.
flatMap은 가장 강력한 RxJava 연산자 중 하나입니다. 각 요소에 대해 비동기 요청을 실행하고 결과를 공통 스트림으로 수집할 수 있습니다. 예를 들어, flatMap은 ID 목록에서 세부 정보를 로드하는 데 사용됩니다: 각 ID → 네트워크 요청 → 결과 병합. 단순히 요소를 변환하는 map과 달리, flatMap은 여러 요소를 발행하거나 다른 Observable로 전환할 수 있어 비동기 파이프라인 구축의 기초가 됩니다.
onErrorResumeNext — 오류 시 백업 Observable로 전환합니다. retry — 오류 시 N회 재구독합니다. onErrorReturn — 오류 대신 기본값을 반환합니다. doOnError — 스트림을 변경하지 않고 오류 시 부작용을 실행합니다(로깅 또는 분석). 이러한 연산자를 결합하면 수동 try/catch 없이 명확한 오류 처리 전략을 가진 강력한 파이프라인을 구축할 수 있습니다.
Schedulers는 Observable과 Observer가 실행될 스레드를 결정합니다. subscribeOn은 소스의 스레드를 설정하고, observeOn은 Observer와 이후 연산자의 스레드를 설정합니다. 이 분리는 RxJava의 핵심 장점입니다: 소스는 IO 스레드, 처리는 computation, UI는 메인 스레드에서 실행됩니다.
주요 Schedulers: Schedulers.io() — I/O 작업용(네트워크, 디스크), 무제한 풀. Schedulers.computation() — 계산용, 코어 수에 따른 고정 풀. Schedulers.newThread() — 각 작업에 새 스레드. AndroidSchedulers.mainThread() — Android 메인 스레드(RxAndroid). Schedulers.trampoline()도 있으며 FIFO 큐로 현재 스레드에서 작업을 실행하여 테스트에 유용합니다.
Google(2025)에 따르면, Schedulers의 올바른 사용은 초보자에게 RxJava에서 가장 어려운 부분입니다. 일반적인 실수는 observeOn 후에 subscribeOn을 호출하는 것으로, 소스에 영향을 미치지 않습니다. subscribeOn은 소스 체인에서 첫 번째여야 하고, observeOn은 UI 구독 전에 위치해야 합니다. 규칙: subscribeOn은 업스트림(소스)에만 영향을 미치고, observeOn은 다운스트림(구독자와 이후 모든 연산자)을 전환합니다.
세 가지 시나리오를 살펴보겠습니다: Single을 사용한 네트워크 요청, zip을 사용한 병렬 요청, debounce를 사용한 검색 필드 디바운스입니다.
Single은 Retrofit 요청에 완벽합니다: 하나의 요청 — 하나의 응답. UI 업데이트를 위해 메인 스레드에서 구독하세요.
api.getUser(id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<User>() {
@Override
public void onSuccess(User user) { showUser(user); }
@Override
public void onError(Throwable e) { showError(e); }
})
zip은 두 개의 독립적인 Single의 결과를 하나로 결합합니다. 병렬로 실행되며, 둘 다 완료된 후 결과가 생성됩니다.
Single.zip(
api.getProfile(),
api.getSettings(),
(profile, settings) -> new Dashboard(profile, settings)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(dashboard -> showDashboard(dashboard), e -> logError(e))
debounce는 빠른 텍스트 변경을 무시하고 400ms의 일시 중지 후에만 요청을 보냅니다. distinctUntilChanged는 텍스트가 변경되지 않은 경우 요청을 취소합니다.
RxTextView.textChanges(searchView)
.debounce(400, TimeUnit.MILLISECONDS)
.filter(text -> text.length() >= 3)
.distinctUntilChanged()
.switchMap(query -> api.search(query))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(results -> showResults(results))
RxJava와 Kotlin Coroutines는 동일한 문제 — 비동기 프로그래밍 — 를 해결하지만 근본적으로 다른 접근 방식을 사용합니다. RxJava는 Observer 패턴을 기반으로 하며 푸시 기반입니다: 소스가 데이터를 보내고 Observer가 반응합니다. 코루틴은 풀 기반입니다: 코드가 await를 통해 순차적으로 데이터를 요청합니다.
Google I/O 2024에 따르면, Kotlin Coroutines는 Android에서 새로운 비동기 코드를 작성할 때 권장되는 접근 방식입니다. RxJava는 기존 프로젝트에서 계속 지원됩니다. Google은 점진적 마이그레이션을 위한 브리징 라이브러리(kotlinx-coroutines-rx3)를 제공합니다. AndroidX(LiveData, Room, Paging 3)는 두 접근 방식을 모두 지원하므로 종속성 충돌 없이 이전 모듈에서는 RxJava를, 새 모듈에서는 코루틴을 사용할 수 있습니다.
점진적 전환: 새 구성 요소는 코루틴으로 작성하고, 이전 RxJava 코드는 그대로 둡니다. RxJava → 코루틴은 awaitSingle() 또는 awaitFirst()를 통해. 코루틴 → RxJava는 future() 또는 asFlowable()을 통해. 대규모 프로젝트의 경우 완전한 마이그레이션에 6~18개월이 소요됩니다.
자주 묻는 질문
Observable은 배압을 지원하지 않습니다 — 소스가 핸들러의 처리 속도보다 빠르게 데이터를 생성하면 MissingBackpressureException이 발생합니다. Flowable은 구성 가능한 버퍼링 전략으로 Reactive Streams 배압을 지원합니다.
subscribeOn은 소스 Observable을 실행할 Scheduler를 설정합니다. observeOn은 체인의 Observer와 이후 모든 연산자의 Scheduler를 설정합니다. subscribeOn은 업스트림에 영향을 미치고, observeOn은 다운스트림에 영향을 미칩니다.
새 프로젝트의 경우 — 네, Google은 코루틴을 권장합니다. 기존 프로젝트의 경우 — kotlinx-coroutines-rx3를 통한 점진적 마이그레이션. RxJava는 레거시 코드에서 안정적으로 지원됩니다.
연산자를 통해: onErrorReturn(기본값), onErrorResumeNext(백업 Observable), retry(N회 재시도). 또는 사용자에게 표시하기 위해 Observer.onError()를 통해 처리합니다.
CompositeDisposable은 여러 구독을 관리하기 위한 컨테이너입니다. dispose()가 호출되면 추가된 모든 구독이 취소됩니다. Activity/Fragment에서 화면이 제거될 때 모든 요청을 취소하는 데 사용됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.