일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- MediaPlayer
- GCP
- list
- SWIFTUI
- databinding
- node.js
- node
- Observable
- Animation
- 동영상
- PagingLib
- SwiftUI Tutorial
- MotionLayout
- mvvm
- rx
- Kotlin
- Reactive
- junit
- 인앱결제
- liveData
- Android
- android13
- paging
- RxKotlin
- mysql
- google play
- 테스트 자동화
- MediaSession
- Koin
- Android 13
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
10. Reactive - 오류 처리 연산자 본문
이번 글에서는 오류 처리 연산자에 대해 설명하도록 하겠습니다.
엡 개발 과정에서 오류는 언제든 발생할 수 있지만 개발자는 사용자가 이를 인지하지 못하고 자연스럽게 동작할 수 있도록 오류를 적절히 관리해야 할 필요가 있습니다.
오류 처리 연산자는 Observable이 발생 시킨 오류를 복구할 수 있도록 도와주는 연산자입니다.
오류 처리 연산자는 오류 발생 시 이벤트를 캐치해서 이후 처리 방안을 지정해주는 “onErrorXXX 계열 연산자”와
오류 발생 시 원천 Observable의 재시도를 지정하는 “retryXXX 계열 연산자”로 구분할 수 있습니다.
- onErrorXXX 계열 연산자
- retryXXX 계열 연산자
onErrorReturn
onErrorReturn 연산자는 Observable에서 아이템 방출 처리 중 에러가 발생했을 때 구독자에게 대체로 방출할 수 있는 기본 값을 지정할 수 있도록 지원하는 연산자 입니다.
사용 방법은 아래와 같습니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map{
it/(3-it)
}.onErrorReturn {
-1
}.subscribe {
println("Next: $it")
}
}
위 코드는 방출하려는 아이템의 값이 3인 경우 map 연산자에서 오류가 발생하도록 되어 강제되어 있는 코드 입니다.
오류 발생 시 onErrorReturn에서 오류를 캐치하여 -1을 방출해주도록 되어 있기 때문에 아래와 같이 출력 됩니다.
Next: 0
Next: 2
Next: -1
onErrorResumeItem
onErrorResumeItem() 연산자는 onErrorReturn 연산자와 동일한 기능을 수행하는 연산자입니다. onErrorResumeItem 연산자 정의를 보면 아래와 같이 내부에서 onErrorReturn 연산자를 호출한 다는 것을 알 수 있습니다.
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
@NonNull
public final Observable<T> onErrorReturnItem(@NonNull T item) {
Objects.requireNonNull(item, "item is null");
return onErrorReturn(Functions.justFunction(item));
}
두 연산자의 차이점은 오류 발생 시 onErrorReturn 연산자는 오류 이벤트를 전달 받을 수 있는 반면 onErrorResumeItem 연산자는 오류 이벤트를 전받 받지 못하고 대체로 방출할 아이템만 정의할 수 있다는 차이입니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map{
it/(3-it)
}.onErrorReturnItem(3)
.subscribe {
println("Next: $it")
}
}
출력 결과는 onErrorReturn 연산자와 동일합니다.
onErrorResumeWith
onErrorResumeWith() 연산자는 오류 발생 시 이벤트로 구독자 넘겨받아 구독자에게 다음 이벤트를 직접적으로 전달하는 오류 처리 연산자 입니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map{
it/(3-it)
}.onErrorResumeWith { observer->
observer.onNext(3)
}.subscribe {
println("Next: $it")
}
}
위 코드를 보면 오류 발생 시 onErrorResumeWith() 연산자 파라미터로 구독자가 넘어오는 것을 확인할 수 있습니다.
이 연산를 사용해 onNext, onError, onComplete를 직접적으로 호출 할 수 있습니다.
위 예제 코드에서는 onNext(3)을 호출 했으므로 아래와 같은 출력 결과를 가집니다.
Next: 0
Next: 2
Next: 3
onErrorResumeNext
오류 발생 시 아이템 방출이 중단되는게 아니라 다른 Observable로 방출을 전환할 필요가 있는 경우도 있는데 이때 유용한 연산자가 onErrorResumeNext 연산자입니다.
onErrorResumeNext 연산자는 에러가 발생했을 시에 다른 Observable을 구독할 수 있도록 합니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map{
it/(3-it)
}.onErrorResumeNext {
Observable.range(10, 5)
}.subscribe {
println("Next: $it")
}
}
위 코드의 경우 세 번째 방출에서 에서 오류가 발생하고 onErrorResumeNext 연산자가 이를 캐치한 후 Observable.range(10, 5)이 아이템 방출을 시작합니다.
출력 결과는 아래와 같습니다.
Next: 0
Next: 2
Next: 10
Next: 11
Next: 12
Next: 13
Next: 14
onErrorComplete
onErrorComplete() 연산자는 오류 발생 시 개발자가 오류 상태를 확인하고 논리 표현식 결과에 따라 complete 이벤트를 보낼 지 error 이벤트를 보낼지 선택할 수 있도록 지원하는 연산자 입니다.
사용 방법은 다음과 같습니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map{
it/(3-it)
}.onErrorComplete {
true
}.subscribeBy(onNext = {
println("Next: $it")
},onError = {
println("Error: $it")
},onComplete = {
println("Completed")
})
}
위 코드에서는 오류 발생 시 onErrorComplete 연산자에서 논리 표현식이 참(true)를 리턴하도록 되어 있으므로 아래와 같은 결과를 출력합니다.
Next: 0
Next: 2
Completed
하지만 onErrorComplete 연산자에서 논리 표현식이 거짓(false)를 리턴한다면 error 이벤트가 전달되므로 아래와 같은 결과를 출력합니다.
Next: 0
Next: 2
Error: java.lang.ArithmeticException: divide by zero
retry
retry() 연산자는 오류가 발생했을 때 동일한 Observable에 연산을 재시도하거나 다시 구독할 수 있도록 지원해주는 오류 처리 연산자 입니다. retry 연산자는 논리 표현식이 참을 반환하는한 계속 재시도하고 거짓을 반환하면 바로 구독자에게 오류를 전달합니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map {
it/(3-it)
}.retry(3)
.subscribeBy (
onNext = {
println("Next: $it")
}, onError = {
println("Error")
})
위 코드는 오류 발생 시 retry(count: 3)을 사용했으므로 오류 발생 시 3회를 재시도하는 코드이므로 출력 결과는 아래와 같습니다.
Next: 0
Next: 2
Next: 0
Next: 2
Next: 0
Next: 2
Next: 0
Next: 2
Error
retryUntil
retryUntil() 연산자는 논리 표현식이 참이면 재시도를 중단하는 연산자로 사용 방법은 아래와 같습니다.
fun funExam(){
var retryCount = 0
Observable
.just(1,2,3,4,5)
.map {
it/(3-it)
}.retryUntil {
(++retryCount == 2)
}.subscribeBy (
onNext = {
println("Next: $it")
}, onError = {
println("Error")
})
}
위 코드를 보면 retryUntil 연산자에서 오류 발생 시 retryCount가 2인 경우 true를 리턴하므로 2가 아닌 경우 계속 재시도를 하므로 아래와 같이 결과가 출력됩니다.
Next: 0
Next: 2
Error
retryWhen
retryWhen() 연산자는 오류 처리 연산자 중 제일 복잡한 연산자로 오류 발생 시 정해진 시간 이후에 정해진 횟수만큼 재시도를 수행하는 연산자 입니다.
아래 예제 코드의 retryWhen 현산자의 인자인 errors는 Observable입니다. 이 상태에서 재시도할 때는 Observable.range(1,3)과 zip() 함수로 두 Observable을 합성합니다.
즉 , 3번의 재시도를 하게됩니다. 그리고 재시도할 때 매번 timer() 함수를 호출하여 retryCount * 1000ms씩 대기 시간을 추가하므로 처음에는 1sec 후에 재시도를 시도하고 이후부터는 2sec 마지막 세번째 재시도는 3sec 후에 하게됩니다.
fun funExam(){
Observable
.just(1,2,3,4,5)
.map {
it/(3-it)
}.retryWhen {
it.zipWith(Observable.range(1, 3), { _: Throwable, i: Int -> i})
.flatMap { retryCount: Int ->
println("retryCount: $retryCount")
Observable.timer((1000*retryCount).toLong(), TimeUnit.MILLISECONDS)
}
}.subscribeBy (
onNext = {
println("Next: $it")
}, onError = {
println("Error")
})
}
출력 결과는 다음과 같습니다.
16:19:30.565 Next: 0
16:19:30.565 Next: 2
16:19:30.566 retryCount: 1
16:19:31.589 Next: 0
16:19:31.589 Next: 2
16:19:31.590 retryCount: 2
16:19:33.593 Next: 0
16:19:33.593 Next: 2
16:19:33.594 retryCount: 3
16:19:36.597 Next: 0
16:19:36.597 Next: 2
정리
이번 글에서는 오류 발생 시 대응할 수 있는 여러가지 오류 처리 연산자에 대해 설명하였습니다.
시작 글에서 언급한 내용을 다시 것 처럼 오류 처리 연산자는 아래와 같이 두가지 계열로 구분할 수 있습니다.
- onErrorXXX 계열: 오류 발생 시 이벤트를 캐치해서 이후 처리 방안을 지정해주는 연산자
- retryXXX 계열: 오류 발생 시 원천 Observable의 재시도를 지정하는 연산자
오류 처리 연산자 세부 내용은 다시 한번 정리하면 아래 표와 같습니다.
다음 글에서는 연산자 종류의 마지막인 “유틸리티 연산자”에 대해 설명하도록 하겠습니다.
'Reactive' 카테고리의 다른 글
11. Reactive - 유틸리티 연산자 (0) | 2021.06.29 |
---|---|
9. Reactive - 조건 연산자 (0) | 2021.06.22 |
8. Reactive - 결합 연산자 (0) | 2021.06.18 |
7. Reactive - 필터 연산자 (0) | 2021.06.16 |
6. Reactive - 변환 연산자 (0) | 2021.06.14 |