일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- SWIFTUI
- Reactive
- php
- PagingLib
- 인앱결제
- MediaPlayer
- node
- SwiftUI Tutorial
- Koin
- databinding
- 테스트 자동화
- mysql
- GCP
- list
- Kotlin
- paging
- MediaSession
- MotionLayout
- node.js
- 동영상
- Animation
- mvvm
- android13
- rx
- Android
- Observable
- google play
- Android 13
- RxKotlin
- junit
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
9. Reactive - 조건 연산자 본문
이번 글에서는 조건 연산자에 대해 설명하도록 하겠습니다.
조건 연산자는 Observeble의 흐름을 제어하는 역할을 합니다. 필터 연산자가 발행된 값을 “채택” or “무시” 여부에 초점을 맞춘다면, 조건 연산자는 지금까지의 흐름을 어떻게 제어할 것인지에 초점을 맞춤니다. Reactive에서 지원하는 조건 연산자의 종류는 다음과 같습니다.
- ambXXX 계열 연산자
- takeXXX 계열 연산자
- skipXXX 계열 연산자
- all 연산자
amb
amb() 연산자는 인스턴스 없이 사용 가능한 연산자로 연산자의 매개변수로 들어온 Observable 중 먼저 아이템을 방출하는 Observable을 사용하고 나머지 Observable의 방출은 무시하는 연산자 입니다.
사용 방법은 아래와 같습니다.
fun funExam(){
val observable1 = Observable
.interval(500, TimeUnit.MILLISECONDS)
.map { "Observable 1 $it" }
val observable2 = Observable
.interval(100, TimeUnit.MILLISECONDS)
.map { "Observable 2 $it"}
Observable.amb(listOf(observable1, observable2))
.subscribe{
println("Next: $it")
}
}
amb 연산자를 사용한 위 코드에서 observable1보다 observable2가 먼저 아이템을 방출했기 때문에 observable1의 방출은 무시되므로 아래와 같은 결과를 출력합니다.
Next: Observable 2 0
Next: Observable 2 1
Next: Observable 2 2
Next: Observable 2 3
Next: Observable 2 4
…
ambWith
ambWith() 연산자는 amb 연산자의 인스턴스 버전으로 amb 연산자와 동일하게 Observable 중 먼저 아이템을 방출하는 Observable을 사용하고 나머지 Observable의 방출은 무시하는 연산자 입니다.
위 예제 코드를 ambWith 연산자로 변경하면 아래와 같습니다.
fun funExam(){
val observable1 = Observable
.interval(500, TimeUnit.MILLISECONDS)
.map { "Observable 1 $it" }
val observable2 = Observable
.interval(100, TimeUnit.MILLISECONDS)
.map { "Observable 2 $it"}
observable1.ambWith(observable2)
.subscribe {
println("Next: $it")
}
}
observable1이 주체가 되어 ambWith 연산자를 사용했지만 observable2가 먼저 아이템을 방출했기 때문에 observable1의 방출은 무시되고 이전과 동일한 결과를 출력합니다.
ambArray
ambArray 연산자는 amb 연산자와 동일한 기능을 수행하는 연산자로 차이점은 amb 연산자는 매개변수로 Obdervable을 list로 형태로 전달받는데 비해 ambArray는 다수 개의 개별 Observale을 전달받습니다. 5개의 Observable을 전달받는 amb와 ambArray 예시 코드는 아래와 같습니다.
fun funExam(){
val observable1 = Observable
.interval(100, TimeUnit.MILLISECONDS)
.map { "Observable 1 $it" }
val observable2 = Observable
.interval(200, TimeUnit.MILLISECONDS)
.map { "Observable 2 $it" }
val observable3 = Observable
.interval(300, TimeUnit.MILLISECONDS)
.map { "Observable 3 $it" }
val observable4 = Observable
.interval(400, TimeUnit.MILLISECONDS)
.map { "Observable 4 $it" }
val observable5 = Observable
.interval(500, TimeUnit.MILLISECONDS)
.map { "Observable 5 $it"}
// 1
Observable.amb(listOf(observable5, observable4, observable3, observable2, observable1))
.subscribe{
println("Next $it")
}
// 2
Observable.ambArray(observable5, observable4, observable3, observable2, observable1)
.subscribe{
println("Next $it")
}
}
위 코드는 amb 연산자와 ambArray 연산자를 사용해 서로 다른 아이템 방출 속도를 가진 5개의 Observable 중 가장 빨리 아이템을 방출하는 Observable의 방출만 채택하는 예제코드로 두 연산자 모두 가장 빠른 방출 속도를 가진 observable1만 방출합니다.
take
take() 연산자는 논리 표현식이 참인 경우(특정 조건이 충족된 경우)에만 아이템을 방출하고자 할 때 사용하는 연산자로 사용 방법은 다음과 같습니다.
fun funExam(){
// 1
Observable
.range(1, 20)
.take(5)
.subscribe {
println("Next 1: $it")
}
// 2
Observable
.interval(100, TimeUnit.MILLISECONDS)
.take(400, TimeUnit.MILLISECONDS)
.subscribe {
println("Next 2: $it")
}
}
첫번째 주석의 Observable에서는 take(5)를 사용하였는데 이는 5개의 아이템만 방출하라는 의미이므로 1~5까지의 아이템을 방출합니다. 두번째 주석의 Observable에서는 take 연산자에 Long value 대신 Time value를 사용하였는데 값을 400ms까지만 아이템 방출을 허용한다는 의미이므로 아래와 같은 결과를 출력합니다.
Next 1: 1
Next 1: 2
Next 1: 3
Next 1: 4
Next 1: 5
Next 2: 0
Next 2: 1
Next 2: 2
takeLast
take 연산자가 시작을 기준으로 조건을 충족하는 아이템만 방출했다면 takeLast() 연산자는 반대로 마지막을 기준으로 아이템을 방출하는 연산자 입니다.
fun funExam() {
Observable
.range(1, 20)
.takeLast(5)
.subscribe {
println("Next: $it")
}
}
즉, 위 예제 코드에서 takeLast(5)를 사용했으므로 마지막 아이템 다섯 개만 방출됩니다.
Next: 16
Next: 17
Next: 18
Next: 19
Next: 20
takeWhile
takeWhile() 연산자는 논리 표현식이 참인 경우에만 아이템을 방출하고 나머지는 건너뛰는 연산자 입니다.
fun funExam() {
Observable
.range(1, 20)
.takeWhile {
it<10
}.subscribe {
println("Next: $it")
}
}
논리 표현식이 참인 경우에만 아이템이 방출되므로 출력 결과는 아래와 같습니다.
Next: 1
Next: 2
Next: 3
…
Next: 9
takeUntil
takeUnitl() 연산자는 다른 Observable이 아이템을 방출하기 직전까지만 아이템을 방출하고 나머지는 건너뛰는 연산자 입니다.
fun funExam(){
val observable1 = Observable.interval(100, TimeUnit.MILLISECONDS)
val observable2 = Observable.interval(500, TimeUnit.MILLISECONDS)
observable1
.takeUntil(observable2)
.subscribe {
println("Next: $it")
}
}
설명대로 위 예제 코드의 observable1은 observable2가 아이템을 방출하기 직전까지만 아이템을 방출하므로 아래와 같은 결과를 출력합니다.
Next: 1
Next: 2
Next: 3
skip
skip() 연산자는 take 연산자와는 반대로 논리 조건식이 맞는 경우(특정 조건을 만족하는 경우) 아이템 방출을 건너뛰는 연산자 입니다.
fun funExam(){
Observable
.range(1, 20)
.skip(5)
.subscribe {
println("Next 1: $it")
}
Observable
.interval(100, TimeUnit.MILLISECONDS)
.skip(400, TimeUnit.MILLISECONDS)
.subscribe {
println("Next 2: $it")
}
}
첫 번째 skip 연산자는 skip(count: Long)를 사용해 처음 5개의 방출을 건너뛰도록 되어 있고
두 번째 skip 연산자는 skip(time: Long, unit: TimeUnit)를 사용해 처음 400ms 동안 발생한 모든 방출을 건너뛰도록 되어 있습니다.
출력 결과는 다음과 같습니다.
Next 1: 6
Next 1: 7
Next 1: 8
…
Next 1: 20
Next 2: 3
Next 2: 4
Next 2: 5
…
skipLast
skipLast 연산자도 skip 연산자와 유사하며 skip 연산자와의 차이점은 뒤에서부터 방출을 건너뛰도록 하는데 있습니다.
fun funExam() {
Observable
.range(1, 20)
.skipLast(5)
.subscribe {
println("Next 1: $it")
}
}
위 예제 코드는 skipLast 연산자를 사용했으므로 맨 뒤의 방출 아이템 5개를 건너 뛰므로 아래와 같은 결과를 출력 합니다.
Next 1: 1
Next 1: 2
Next 1: 3
…
Next 1: 15
skipWhile
skipWhile 연산자는 논리 표현식을 기반으로 건너뛰는 연산자로 필터 연산자와 마찬가지로 논리 표현식을 skipWhile 연산자에 전달합니다. 논리 표현식이 참이라고 평가되면 방출을 건너뛰고 거짓이라고 평가되는 순간부터 모든 아이템을 방축하기 시작합니다.
fun funExam() {
Observable
.range(1, 20)
.skipWhile {
it<10
}.subscribe {
println("Next 1: $it")
}
}
skipWhile 연산자를 사용한 위 예제는 10보다 작은 경우에 방출을 건너뛰도록 되어 있으므로 아래와 같이 결과를 출력합니다.
Next 1: 10
Next 1: 11
Next 1: 12
…
Next 1: 20
skipUntil
skipUntil 연산자는 동시에 두 개의 Observable이 작업하는 상황에서 Observable 2가 아이템 방출을 시작하자마자 Observable 1의 아이템을 방출하고자 할때 사용하는 연산자입니다.
fun funExam(){
val observable1 = Observable.interval(100, TimeUnit.MILLISECONDS)
val observable2 = Observable.interval(500, TimeUnit.MILLISECONDS)
observable1
.skipUntil(observable2)
.subscribe {
println("Next: $it")
}
}
skipUntil 연산자에 observable2를 사용했는데 observable2는 500ms 뒤에 push를 시작하도록 되어 있으므로 observable2가 push를 시작하기 전까지
observable1의 모든 아이템 방출은 건너뛰므로 아래와 같이 출력됩니다.
Next: 4
Next: 5
Next: 6
Next: 7
Next: 8
…
all
all() 연산자는 주어진 조건에 모두 맞을 때만 true값을 뱡출하고 조건에 맞지 않을 때는 false 값을 방출하는 연산자 입니다.
fun funExam(){
// 1
Observable
.range(1, 20)
.all {
it<10
}.subscribeBy(onSuccess = {
println("onSuccess 1: $it")
})
// 2
Observable
.range(1, 20)
.all {
it>0
}.subscribeBy(onSuccess = {
println("onSuccess 2: $it")
})
}
첫번째 Observable은 방출하는 값이 all 연산자의 조건을 모두 충족하지 못하므로 false가 방출되며
두번째 Observable은 방출하는 값이 all 연산자의 조건을 모두 충족하므로 true가 방출되므로 출력 결과는 아래와 같습니다.
onSuccess 1: false
onSuccess 2: true
정리
이번 글에서는 조건 연산자에 대해 알아보았습니다.
여러 개의 Observable 중 먼저 아이템을 방출하는 Observable만 취하는 ambXXX 계열 연산자와
논리 표현식에 맞는 아이템만 방출하는 takeXXX 계열 연산자 그리고 takeXXX 계열 연산자와는 반대로
논리 표현식에 맞을 때에는 아이템만 방출을 건너뛰는 skipXXX 계열 연산자 마지막으로 모든 조건이 만족할 때에만 true를 방출하는 all 연산자까지 알아보았습니다.
다음 글에서는 오류 처리 연산자에 대해 설명하도록 하겠습니다.
'Reactive' 카테고리의 다른 글
11. Reactive - 유틸리티 연산자 (0) | 2021.06.29 |
---|---|
10. Reactive - 오류 처리 연산자 (0) | 2021.06.25 |
8. Reactive - 결합 연산자 (0) | 2021.06.18 |
7. Reactive - 필터 연산자 (0) | 2021.06.16 |
6. Reactive - 변환 연산자 (0) | 2021.06.14 |