Android/RxJava
Android RxJava - 예외 처리
강태종
2022. 3. 8. 18:01
RxJava 예외 처리
기본적으로 Observer의 onError 함수를 통해서 에러를 처리할 수 있습니다. onError로 에러를 처리하는 경우 스트림은 데이터 발행을 중단하며 Observer는 onComplete 호출을 하지 못합니다.
fun onError() {
Observable.create<String> { emitter ->
emitter.onNext("Message 1")
emitter.onNext("Message 2")
throw Exception("Something Wrong")
}.subscribe({
println(it)
}, {
println("Error : $it")
})
}
Message 1
Message 2
Error : java.lang.Exception: Something Wrong
Rx에서는 onError를 사용한 경우 데이터 스트림이 손상되어 복구할 수 없다고 표현하고, 이러한 방법을 최후의 수단이라고 설명하고 있습니다. Rx는 연산자를 통해 손상을 복구할 수 있으며, 전역으로 에러를 관리할 수 있습니다.
아래의 방법은 공식문서에서 권장하는 손상 복구 방법입니다. (링크)
- Error를 삼키고 흐름을 계속 할 수 있는 백업 Observable로 교체한다.
- Error를 삼키고 기본 값을 발행한다.
- Error를 삼키고 즉시 실패한 Observable를 다시 시작한다.
- Error를 삼키고 일정 시간 기다렸다가 실패한 Observable를 다시 시작한다.
onErrorResumeNext
에러가 발생했을 때 백업 Observable로 교체하는 방법입니다.
fun onErrorResumeNext() {
Observable.create<String> { emitter ->
emitter.onNext("Message 1")
emitter.onNext("Message 2")
throw Exception("Something Wrong")
}.onErrorResumeNext {
Observable.just(it.message ?: "")
}.subscribe({
println("onNext : $it")
}, {
println("onError : $it")
}, {
println("onComplete")
})
}
onNext : Message 1
onNext : Message 2
onNext : Something Wrong
onComplete
onErrorReturn
에러가 발생했을 때 기본 값을 반환하는 방법입니다.
fun onErrorReturn() {
Observable.create<String> { emitter ->
emitter.onNext("Message 1")
emitter.onNext("Message 2")
throw Exception("Something Wrong")
}.onErrorReturn {
"Message ${it.message}"
}.subscribe({
println("onNext : $it")
}, {
println("onError : $it")
}, {
println("onComplete")
})
}
onNext : Message 1
onNext : Message 2
onNext : Message Something Wrong
onComplete
retry
에러가 발생했을 때 즉시 재시도하는 방법입니다. 횟수나, Exception으로 재시도 여부를 판단할 수 있습니다.
fun retry() {
Observable.create<String> { emitter ->
emitter.onNext("Message 1")
emitter.onNext("Message 2")
throw Exception("Something Wrong")
}.retry().subscribe({
println("onNext : $it")
}, {
println("onError : $it")
}, {
println("onComplete")
})
}
onNext : Message 1
onNext : Message 2
onNext : Message 1
onNext : Message 2
...
retryWhen
retry에 좀 더 조건을 줄 수 있습니다.
take를 통해 retry count를 정하고, flatMap, timer를 통해 대기 시간을 설정했습니다.
fun retryWhen() {
Observable.create<String> { emitter ->
println("Observable")
emitter.onNext("Message 1")
emitter.onNext("Message 2")
throw Exception("Something Wrong")
}.retryWhen {
it.take(3).flatMap {
Observable.timer(3, TimeUnit.SECONDS)
}
}.subscribe({
println("onNext : $it")
}, {
println("onError : $it")
}, {
println("onComplete")
})
Thread.sleep(30000L)
}
Observable
onNext : Message 1
onNext : Message 2
Observable
onNext : Message 1
onNext : Message 2
Observable
onNext : Message 1
onNext : Message 2
Observable
onNext : Message 1
onNext : Message 2
onComplete
전역 이벤트
에러가 발생했을 때 전역에서 공통으로 발생하는 이벤트는 하나의 클래스에서 관리하는 것이 효율적입니다. 여러 곳에 코드를 입력하면 중복된 코드가 발생하고 유지 보수에 어려움이 있습니다. 예를 들어 에러가 발생했을 때 서버로 로그를 보내거나, 통계를 집계하는 경우가 있습니다.
fun setErrorHandler() {
RxJavaPlugins.setErrorHandler {
println("ErrorHandler : ${it.message}")
}
Observable.create<String> { emitter ->
emitter.onError(Exception("Something Wrong"))
}.subscribe {
println(it)
}
}
ErrorHandler : The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | java.lang.Exception: Something Wrong