🔔 앞으로의 Reactive X 시리즈는 RxJava, RxKotlin 기준으로 작성됩니다.
이전 포스팅 [Single, Maybe, Completable] 과 이어집니다.

이전 포스팅에서 Observable 을 생성하는 방법과 이외 특별한(?) 데이터 스트림들에 대해서도 알아보았다. 우리가 알아본 Observable 은 크게 두 가지로 나눌 수 있는데, 오늘은 이에 대해서 알아보고자 한다.

Cold Observable & Hot Observable

Observable 은 Cold Observable 과 Hot Observable 로 나눌 수 있는데, 차이는 요약하자면 이렇다.

  • Cold Observable : 생성된 이후 누군가 구독을 요청했을 때 '처음부터' 데이터 발행
  • Hot Observable : 데이터 발행 시작한 이후 모든 구독자들에게 '같은' 데이터 발행

아직 잘 와닿지는 않을 것이다. 그럼 지금부터 각각의 개념을 톺아보자.

Cold Observable

지금까지 다뤘던 녀석들 처럼 Observable'구독'을 요청했을 때 데이터를 발행하기 시작한다. 즉, 누군가 구독을 하지 않으면 데이터를 발행하지 않는다. 또한 데이터를 처음부터 끝까지 발행하는 것을 보장한다.

아래 예시를 살펴보자. 1초, 2초, 3초 ... 데이터를 발행하는 Observable 를 구독하는 두 개의 구독자가 있다. 첫 번째 구독자가 구독을 하고, 2초 후에 두 번째 구독자가 구독을 하는 모습이다. 그리고 결과를 살펴보자.

fun main() {
    val stream = Observable.interval(1, TimeUnit.SECONDS)
    stream.subscribe {
        println("First Subscriber : $it")
    }
    Thread.sleep(2000)
    stream.subscribe {
        println("Second Subscriber : $it")
    }
    Thread.sleep(2000)
}
First Subscriber : 0
First Subscriber : 1
First Subscriber : 2
Second Subscriber : 0
First Subscriber : 3
Second Subscriber : 1

두 번째 구독자가 구독을 시작했을 때, 첫 번째 구독자가 받을 '3' 이 발행되는 것이 아닌 처음부터 데이터가 발행되는 것을 보면 위에서 언급했던 '데이터를 처음부터 끝까지 발행하는 것을 보장'하는 점을 알 수 있다.

같은 stream 이라는 Observable 인스턴스를 사용했음에도, Observer (Subscriber) 마다 다른 Observable Stream 이 생성되게 되어있다. 우리가 유튜브에 올라와있는 영상을 볼 때, 다른 사람이 보던 부분부터 재생되는게 아니라 처음부터 영상이 재생된다. 이것이 Cold Observable 이다.

따라서 실제로는 데이터를 요청하고 결과를 받는 네트워킹 (HTTP 요청 등) 동작, DB 트랜잭션 (쿼리) 등에 사용된다.

유튜브 → Cold Observable 비유

  • 어떤 사용자가 클릭한 영상 재생 시작 → Observer 가 구독 시작 + Observable 데이터 발행 시작
  • 누가 재생하든 무조건 영상 맨 처음부터 → 어떤 Observer 가 구독하든 무조건 데이터 맨 처음부터

Hot Observable

Cold Observable 과 다르게, 구독자의 존재 여부와 상관없이 데이터를 발행하는 녀석이다. 데이터 발행이 시작된 이후로 모든 구독자에게 동시에 같은 데이터를 발행한다. 위 예시로 따져봤을 때, 두 번째 구독자가 구독을 시작할 때 두 번째 구독자에게도 첫 번째 구독자가 받을 '3' 이 발행되는 느낌이다. 따라서 구독을 늦게 했다면 데이터를 처음부터 받지 못한다. '나는 데이터 발행하고 있으니, 니들이 받든 말든 알아서 해라' 뉘앙스이다.

안드로이드를 예로 들면 '클릭 이벤트' 등의 UI 이벤트에 사용된다. Observer 가 있든 말든 이벤트는 계속 발생된다. Observer 들은 이를 '구독한 이후에 발생'하는 이벤트를 받아보게 된다.

ConnectableObservable

아래 예시를 살펴보자. Hot Observable 구현을 위해, ConnectableObservable 이라는 특수한 Observable 을 사용한다. 처음보는 publish()connect() 라는 메소드에 집중해보자.

fun main() {
    // 물론 ConnectableObservable 데이터 타입 생략 가능
    // publish() 를 붙이는 순간 Hot Observable 로 변환됨
    val stream: ConnectableObservable<Long> =
        Observable.interval(1, TimeUnit.SECONDS).publish()

    // connect() 가 호출될 때 곧바로 데이터 발행 시작
    stream.connect()

    stream.subscribe {
        println("First Subscriber : $it")
    }
    Thread.sleep(2000)
    stream.subscribe {
        println("Second Subscriber : $it")
    }
    Thread.sleep(2000)
}
First Subscriber : 0
First Subscriber : 1
First Subscriber : 2
Second Subscriber : 2
First Subscriber : 3
Second Subscriber : 3

차이가 느껴지는가? 다른 구독자가 들어오든 말든, 발행하고 있던 데이터를 계속하여 발행한다. 유튜브 라이브 스트리밍를 떠올려보자. 특별히 시청자의 요청에 의해서 라이브를 시작하는 것이 아닌, 일단 유튜버가 라이브를 키면 시청자들이 들어오든 말든 하는 것이다. 그리고 늦게 들어간 시청자는 앞 부분을 보지 못한다. 이것이 Hot Observable 개념이다.

ConnectableObservablepublish() 를 붙이는 순간 해당 스트림은 Hot Observable 이 된다. 그리고 connect() 라는 녀석이 호출될 때 누가 구독하고 있든 말든 데이터 발행을 시작하는 것이다.

유튜브 → Hot Observable 비유

  • 유튜버가 라이브 스트리밍 시작 → Observable 데이터 발행 시작
  • 어떤 사용자가 라이브 시작 30분 후에 들어옴 → 어떤 Observer 가 구독 시작
    • 단, 지나간 앞의 30분 영상은 못 봄 → 단, 이전에 이미 발행된 데이터는 받지 못함

이번 포스팅에선 크게 두 가지로 나눌 수 있는 Observable 유형에 대하여 알아보았다. 다음 포스팅에선 Disposable 개념에 대해 알아보고자 한다.

profile
어려울수록 기본에 미치고 열광하라

2개의 댓글

comment-user-thumbnail
2021년 8월 28일

이해가 쏙쏙 되네요 ㅎㅂㅎ

1개의 답글