🔔 앞으로의 Reactive X 시리즈는 RxJava, RxKotlin 기준으로 작성됩니다
공식 문서를 참고하여 작성된 포스팅입니다.
이전 포스팅과 이어집니다.
Observable 을 변형한다 함은, 데이터를 특정 형태로 변형하여 발행하는 것이다. 어떤 비동기 기능을 개발할 때, 상황에 따라 알맞은 형태로 반환받고 싶어질 때가 있다. 이럴 때를 대비하여 이번 포스팅에서는, Observable 을 변형하는 다양한 연산자들에 대하여 알아보자.
우리는 버퍼 라는 단어 자체를 많이 본 적이 있고, 대략 어떤 역할을 하는 녀석인지도 알고 있다. buffer()
메소드 역시 비슷한 동작을 하게 된다.
아래 코드를 통해 동작을 이해해보자.
fun main() {
Observable.range(0, 8)
.buffer(3)
.subscribe {
println("마! 이게 버퍼다!")
it.forEach {
println(it)
}
}
}
마! 이게 버퍼다!
0
1
2
마! 이게 버퍼다!
3
4
5
마! 이게 버퍼다!
6
7
buffer(3)
이하 함은, Observable 이 발행하는 데이터를 3개 씩 버퍼링하여 데이터를 발행해주는 역할을 한다. List
형태로 데이터들을 묶어준다. 출력 결과를 보면 이해될 것이다.
얘는 Observable 이 발행하는 데이터 하나 하나를, 지정한 함수 동작로 매핑해서 값을 변환한다. 필자는 개인적으로 'Observable 변환' 이라하면 가장 먼저 떠오르는 녀석이 map()
인 것 같다.
아래 코드를 보면, 발행되는 데이터 각각에 10을 곱하고 이를 String
으로 변환하여 반환한다.
fun main() {
val intStream = Observable.just(1, 2, 3)
val stringStream = intStream.map {
(it * 10).toString()
}
stringStream.subscribe {
println("[${it.javaClass}] : $it")
}
}
[class java.lang.String] : 10
[class java.lang.String] : 20
[class java.lang.String] : 30
이 녀석은 Observable 에서 발행된 데이터들 각각에 대해서, map
처럼 다른 값으로 변환하여 이를 또 다른 Observable 형태로 반환해주는 역할을 한다. 반환 형태가 결국 Observable 이기 때문에 새롭게 생성된 데이터들이 하나씩 순서대로 발행되는 Flatten 된 형태이다.
코드를 보며 이해해보자.
fun main() {
val stream = Observable.just("A", "B", "C")
stream.flatMap {
Observable.just(
"[$it] - 1",
"[$it] - 2"
)
}.subscribe {
println(it)
}
}
[A] - 1
[A] - 2
[B] - 1
[B] - 2
[C] - 1
[C] - 2
발행되는 데이터 각각에 대해 새로운 Observable 를 생성하여, 지정된 특정 연산을 거쳐 Flatten 되어 Observable 형태로 발행되는 새로운 데이터들을 받아볼 수 있다.
flatMap()
은 Observable 작업을 여러 번 연계하여 사용할 때 유용하다.
scan()
은 발행된 데이터를 다음에 발행되는 데이터의 첫 번째 인자로 전달해주는 녀석이다.
위의 예시 마블 다이어그램대로 코드를 짜보자.
fun main() {
Observable.just("A", "B", "C", "D", "E")
.scan { x: String, y: String ->
x + y
}
.subscribe {
println(it)
}
}
A
AB
ABC
ABCD
ABCDE
즉, 데이터를 발행하면 해당 데이터를 다음에 발행되는 데이터의 첫 번째 인자 ( x
) 로 전달한다.
이 외에도 groupBy
, window
등의 녀석들이 있으니 꼭 공식문서를 통해 추가적으로 공부해보길 바란다.