본문 바로가기

Language/RxJava

[RxJava] 7장. 디버깅과 예외 처리 1 - 디버깅(Debugging)

728x90

디버깅

  • RxJava 코드는 로그를 넣을 수 있는 공간이 없다.
  • Observable로 시작하는 업스트림과 그것을 받아서 처리하는 다운스트림이 동일한 문장으로 이루어져 있기 때문.
  • 따라서, doOnXXX() 계열 함수를 이용하여 부수 효과를 일으켜 디버깅을 수행한다.

doOnNext(), doOnComplete(), doOnError() 함수

이 3가지 함수는 Observable의 알림 이벤트에 해당한다.

  • doOnNext는 Observable이 어떤 데이터를 발행할 때 발생.
  • doOnComplete는 Observable이 모든 데이터를 발행할 때 발생.
  • doOnError는 중간에 에러가 발생할 때 발생.
Observable<String> source = Observable.fromArray(exam);

source.doOnNext(data -> Log.d("onNext()", data))
	.doOnComplete(() -> Log.d("onComplete"))
	.doOnError(e -> Log.e("error", e.errorMessage()))
	.subscribe(Log::i);
    

// 출력 결과
main | onNext() | debug = data1
main | value = data1
main | onNext() | debug = data2
main | value = data2
main | debug = onComplete()

...
main | onError() | error = errorMessage

 

모두 Main 스레드에서 실행되며 각 이벤트 발생 시에는 debug 로그를 출력한다.

 

 

doOnEach() 함수

onNext, onComplete, onError 이벤트를 한 번에 처리할 수 있다.

 

Observable<String> source = Observable.fromArray(exam);

source.doOnEach(noti ->
	if (noti.isOnNext()) Log.d("onNext()", noti.getValue());
	if (noti.isOnComplete()) Log.d("onComplete()");
	if (noti.isOnError()) Log.e("onError()", noti.getError().getMessage());
}).subscribe(Log::i);


// 출력 결과
main | onNext() | debug = data1
main | value = data1
main | onNext() | debug = data2
main | value = data2
main | debug = onComplete()

...
main | onError() | error = errorMessage

 

doOnEach 함수는 오직 onNext, onError, onComplete 이벤트만 처리하기 때문에 onSubscribe() 함수는 호출되지 않는다.

 

 

doOnSubscribe(), doOnDispose() 함수

  • doOnSubscribe 함수는 Observable을 구독했을 때 어떤 작업을 할 수 있다.
  • doOnDispose 함수는 Observable의 구독을 해지했을 때 호출되며 인자는 Action 객체이다.
    • 스레드 다수에서 Observable을 참조할 수 있기 때문에 Action 객체는 '스레드 안전'하게 동작해야 한다.
    • Disposable 객체를 선언하여 dispose() 함수 선언 시 발생한다.
Observable<String> source = Observable.fromArray(exam)
	.zipWith(Observable.interval(100L, TimeUnit.MILLISECONDS), (a, b) -> a)
	.doOnSubscribe(d -> Log.d("onSubscribe()"))
	.doOnDispose(() -> Log.d("onDispose()"));
    
Disposable d = source.subscribe(Log::i);

CommonUtils.sleep(1000);
d.dispose();
CommonUtils.sleep(1000);


// 출력 결과
main | debug = onSubscribe()
Thread-1 | value = data1
Thread-1 | value = data2
main | debug = onDispose()

 

두 함수는 main 스레드에서 수행이 되며, d.dispose()가 호출 된 후에 onDispose가 출력된다.

 

doOnLifeCycle() 함수 

doOnSubscribe와 doOnDispose를 한번에 호출하는 함수.

 

Observable<String> source = Observable.fromArray(exam)
	.zipWith(Observable.interval(100L, TimeUnit.MILLISECONDS), (a, b) -> a)
	.doOnLifeCycle(d -> Log.d("onSubscribe()"), () -> Log.d("onDispose()"));

Disposable d = source.subscribe(Log::i);

CommonUtils.sleep(1000);
d.dispose();
CommonUtils.sleep(1000);


// 출력 결과
main | debug = onSubscribe()
Thread-1 | value = data1
Thread-1 | value = data2
main | debug = onDispose()

 

위의 doOnSubscribe 관련 예제에서 doOnSubscribe와 doOnDispose를 doOnLifeCycle 함수로 교체하기만 한 것이다.

 

 

doOnTerminate() 함수

Observable이 끝나는 조건인 onComplete 혹은 onError 이벤트가 발생했을 때 실행하는 함수.

정확히는 해당 이벤트 발생 직전에 호출한다.

 

Observable<String> source = Observable.fromArray(exam);

source.doOnTerminate(() -> Log.d("onTerminate()"))
	.doOnComplete(() -> Log.d("onComplete()"))
	.doOnError(e -> Log.d("onError()", e.getMessage()))
	.subscribe(Log::i);
    

// 출력 결과
main | value = 1
main | value = 2
main | value = 3
main | debug = onTerminate()
main | debug = onComplete()

 

출력 결과를 보면 onComplete가 호출되기 전에 onTerminate가 호출된 것을 볼 수 있다.

마찬가지로, onError가 발생하게 되면 onError가 호출되기 전에 onTerminate가 호출될 것 이다.

728x90