본문 바로가기
Android 개발/Debug, ADB, CrashLytics, LogCat

RxJava2의 Global Error Handler 대응 #UndeliverableException

by Developer88 2019. 10. 16.
반응형

오늘은 RxJava2의 Global Error Handler에 대해서 정리해 보도록 하겠습니다.

이 글은 UndeliverableException이 발생하는 케이스에 대응하는 방법이기도 한데요.

재현하기가 쉽지만은 않은 케이스입니다.

하지만, 프로덕트로 Playstore에 출시하게 되고, 다양한 기기와 상황에서에서는

언젠가는 마주치게 되는 Exceptoin이기도 합니다.

 

1. 문제

아래와 같이 이미 cancel되었거나 dispose되어서 consumer가 갈 곳이 없다고 나와있습니다.

무슨 Exception이길레, 해결할 방법에 대한 link까지 제공해 주고 있는 것일까요?

 

 

이것은  RxJava2로 업그레이드 하면서, 달라진 ErrorHandler를 적용하지 않아서 발생한 문제인데요.

이것이 무엇이고 왜 해야하는지 아래에서 정리해 보겠습니다.

 

2. RxJava2의 GlobalErrorHandler

RxJavaPlugins.onError는 GlobalErrorHandler인데요.

그런데, 왜 RxJava1에 없던 Global핸들러를 만든었을까요?

그 이유에 대해서 RxJava에서는 다음과 같이 설명하고 있습니다.

Exception이 생겨서 onError처리를 하기 전에,

스트림이 끝나버리거나 취소되는 경우 에러가 길을 잃을 수 있다고 합니다.

물론 앱이 죽지 않는다는 사실만으로는 좋을 수 있지만,

잠재적인 bug를 찾지 못하게 되는 상황이 될 수 있기 때문에

이러한 에러들이 갈 곳을 만들고, 그 에러들에 대한 처리를 하기 위해서,

Global핸들러를 만들었다고 하는군요.

 

위에서 영어문장으로 나왔던 "could not be delivered"라고 나왔다는 것은,

exception이 나왔는데, stream이 끊어졌다거나 취소되서 갈 곳이 없다는 것이지요.

 

아무리 스트림상으로 onError처리를 해 주었다고 해도,

이렇게 그 곳으로 갈 곳 없는 Exception들은 GlobalErrorHandler에서 처리해 주어야 합니다.

 

3. RxJavaPlugin Error Handle

이것을 처리하는 코드의 위치는 application클래스가 적합할 것 같은데요.

아래와 같이 에러처리를 해 줍니다.

주석을 보시면 아시겠지만,

일부는 처리해야할 exception이 아니므로, return만 해주고 넘어갑니다.

예를 들면, IOException이라든가, InterruptedException의 경우,

스트림의 onError에서의 처리가 아닌, 이곳에서는 그냥 return만 하고,

로그만 남기고 return해 줍니다.

반면 NullPointerException이나 IllegalArgumentException같은 경우는

 

 

 

kotlin으로는 아래코드와 같습니다.

 

RxJavaPlugins.setErrorHandler {
            var error = it
            if (error is UndeliverableException) {
                error = it.cause
            }
            if (error is IOException || error is SocketException) {
                // fine, irrelevant network problem or API that throws on cancellation
                return@setErrorHandler
            }
            if (error is InterruptedException) {
                // fine, some blocking code was interrupted by a dispose call
                return@setErrorHandler
            }
            if (error is NullPointerException || error is IllegalArgumentException) {
                // that's likely a bug in the application
                Thread.currentThread().uncaughtExceptionHandler
                        .uncaughtException(Thread.currentThread(), error)
                return@setErrorHandler
            }
            if (error is IllegalStateException) {
                // that's a bug in RxJava or in a custom operator
                Thread.currentThread().uncaughtExceptionHandler
                        .uncaughtException(Thread.currentThread(), error)
                return@setErrorHandler
            }
            Log.d("RxJavaPluginError",
                    "Undeliverable exception received, not sure what to do", error)
        }

이제는 갈곳없는 Exception이 갈 자리를 만들어 주었으므로,

이전에 있었던 Exception은 더이상 발생하지 않게 됩니다.

 

ErrorHandling에 대해 더 좋은 방법이 있다면 이 글을 통해 업데이트 하도록 하겠습니다.

 

728x90

댓글