ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디버깅(Debugging)
    BackEnd/RxJava 2023. 7. 15. 07:00
    반응형

      RxJava 프로그래밍은 데이터를 생성 및 통지하고 이를 구독하여 처리하는 과정이 하나의 문장으로 되어 있습니다. 즉, RxJava 프로그래밍은 선언적 프로그래밍 방식이기 때문에 데이터의 상태 변화를 확인하기 위한 디버깅이 쉽지 않습니다. 또한, RxJava 프로그래밍은 여러 쓰레드가 동시에 실행되는 비동기 프로그래밍이기 때문에 실행 시 항상 같은 결과가 나온다는 보장을 할 수 없습니다.

     

      이러한 문제점을 해결하기 위해 RxJava에서는 doXXX로 시작하는 함수를 통해 생산자나 소비자쪽에서 이벤트 발생 시 로그를 기록할 수 있는 방법을 제공합니다. 따라서 소비자가 전달 받은 데이터를 처리하기 전 원본 데이터의 상태나 변환 및 필터링 등으로 가공되는 시점의 데이터 상태를 doXXX 함수를 통해 쉽게 파악할 수 있습니다.

     

    doOnSubscribe

    • 구독 시작 시 지정된 작업을 처리할 수 있습니다.
    • onSubscribe 이벤트가 발생하기 직전에 실행됩니다.

    package com.itvillage.section02;
    
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import io.reactivex.Observable;
    
    /**
     * onSubscribe 이벤트 발생 전에 호출되는 doOnSubscribe 의 사용 예제
     */
    public class DoOnSubscribeExample {
        public static void main(String[] args) {
            Observable.just(1, 2, 3, 4, 5, 6, 7)
                    .doOnSubscribe(disposable -> Logger.log(LogType.DO_ON_SUBSCRIBE, "# 생산자: 구독 처리 준비 완료"))
                    .subscribe(
                            data -> Logger.log(LogType.ON_NEXT, data),
                            error -> Logger.log(LogType.ON_ERROR, error),
                            () -> Logger.log(LogType.ON_COMPLETE),
                            dispose -> Logger.log(LogType.ON_SUBSCRIBE, "# 소비자: 구독 처리 준비 완료 알림 받음")
                    );
        }
    }

     

    doOnNext

    • 생산자가 데이터를 통지하는 시점에 지정된 작업을 처리할 수 있습니다.
    • onNext 이벤트가 발생하기 직전에 실행됩니다.
    • 통지된 데이터가 함수형 인터페이스의 파라미터로 전달되므로 통지 시점마다 데이터의 상태를 확인할 수 있습니다.

    package com.itvillage.section02;
    
    
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import io.reactivex.Observable;
    
    /**
     * 데이터 통지 시 마다 실행되는 doOnNext 를 이용해 데이터의 상태를 확인하는 예제
     */
    public class DoOnNextExample {
        public static void main(String[] args) {
            Observable.just(1, 3, 5, 7, 9, 10, 11, 12, 13)
                    .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, "# 원본 통지 데이터: " + data))
                    .filter(data -> data < 10)
                    .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, "# filter 적용 후: " + data))
                    .map(data -> "#### " + data + " ####")
                    .doOnNext(data -> Logger.log(LogType.DO_ON_NEXT, "# map 적용 후: " + data))
                    .subscribe(data -> Logger.log(LogType.ON_NEXT, "# 최종 데이터: " + data));
        }
    }

     

    doOnComplete

    • 생산자가 완료를 통지하는 시점에 지정된 작업을 처리할 수 있습니다.
    • onComplete 이벤트가 발생하기 직전에 실행됩니다.

    package com.itvillage.section02;
    
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import io.reactivex.Observable;
    
    /**
     * onComplete 이벤트 발생 전에 호출되는 doOnComplete 의 사용 예제
     */
    public class DoOnCompleteExample {
        public static void main(String[] args) {
            Observable.range(1, 5)
                    .doOnComplete(() -> Logger.log(LogType.DO_ON_COMPLETE, "# 생산자: 데이터 통지 완료"))
                    .subscribe(
                            data -> Logger.log(LogType.ON_NEXT, data),
                            error -> Logger.log(LogType.ON_ERROR, error),
                            () -> Logger.log(LogType.ON_COMPLETE)
                    );
        }
    }

     

    doOnError

    • 생산자가 에러를 통지하는 시점에 지정된 작업을 처리할 수 있습니다.
    • onError 이벤트가 발생하기 직전에 실행됩니다.
    • 통지된 에러 객체가 함수형 인터페이스의 파라미터로 전달되므로 에러 상태를 확인할 수 있습니다.

    package com.itvillage.section02;
    
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import io.reactivex.Observable;
    
    /**
     * onError 이벤트 발생 전에 호출되는 doOnError 의 사용 예제
     */
    public class DoOnErrorExample {
        public static void main(String[] args) {
            Observable.just(3, 6, 9, 12, 15, 20)
                    .zipWith(Observable.just(1, 2, 3, 4, 0, 5), (a, b) -> a / b)
                    .doOnError(error -> Logger.log(LogType.DO_ON_ERROR, "# 생산자: 에러 발생 - " + error.getMessage()))
                    .subscribe(
                            data -> Logger.log(LogType.ON_NEXT, data),
                            error -> Logger.log(LogType.ON_ERROR, error)
                    );
        }
    }

     

    doOnEach

    • doOnNext, doOnComplete, doOnError를 한 번에 처리할 수 있습니다.
    • Notification 객체를 함수형 인터페이스의 파라미터로 전달 받아서 처리합니다.

    package com.itvillage.section02;
    
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import io.reactivex.Observable;
    
    /**
     * doOnEach 를 이용해 doOnNext, doOnComplete, doOnError를 한꺼번에 처리하는 예제
     */
    public class DoOnEachExample {
        public static void main(String[] args) {
            Observable.range(1, 5)
                    .doOnEach(notification -> {
                        if(notification.isOnNext())
                            Logger.log(LogType.DO_ON_NEXT, "# 생산자: 데이터 통지 - " + notification.getValue());
                        else if(notification.isOnError())
                            Logger.log(LogType.DO_ON_ERROR, "# 생산자: 에러 발생 - " + notification.getError());
                        else
                            Logger.log(LogType.DO_ON_COMPLETE, "# 생산자: 데이터 통지 완료");
                    })
                    .subscribe(
                            data -> Logger.log(LogType.ON_NEXT, data),
                            error -> Logger.log(LogType.ON_ERROR, error),
                            () -> Logger.log(LogType.ON_COMPLETE)
                    );
        }
    }

     

    doOnCancel / doOnDispose

    • Flowable에서는 doOnCancel, Observable에서는 doOnDispose 함수를 사용합니다.
    • 소비자가 구독을 해지하는 시점에 지정된 작업을 처리할 수 있습니다.
    • 완료나 에러로 종료될 경우에는 실행되지 않습니다.

    package com.itvillage.section02;
    
    import com.itvillage.common.CarMaker;
    import com.itvillage.common.SampleData;
    import com.itvillage.utils.LogType;
    import com.itvillage.utils.Logger;
    import com.itvillage.utils.TimeUtil;
    import io.reactivex.Observable;
    import io.reactivex.Observer;
    import io.reactivex.disposables.Disposable;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * 구독 해지 시 doOnDispose 를 이용하여 지정한 처리를 하는 예제
     */
    public class DoOnDisposeExample {
        public static void main(String[] args) {
            Observable.fromArray(SampleData.carMakers)
                    .zipWith(Observable.interval(300L, TimeUnit.MILLISECONDS), (carMaker, num) -> carMaker)
                    .doOnDispose(() -> Logger.log(LogType.DO_ON_DISPOSE, "# 생산자: 구독 해지 완료"))
                    .subscribe(new Observer<CarMaker>() {
                        private Disposable disposable;
                        private long startTime;
                        @Override
                        public void onSubscribe(Disposable disposable) {
                            this.disposable = disposable;
                            this.startTime = TimeUtil.start();
                        }
    
                        @Override
                        public void onNext(CarMaker carMaker) {
                            Logger.log(LogType.ON_NEXT, carMaker);
                            if(TimeUtil.getCurrentTime() - startTime > 1000L){
                                Logger.log(LogType.PRINT, "# 소비자: 구독 해지 , 1000L 초과");
                                disposable.dispose();
                            }
                        }
    
                        @Override
                        public void onError(Throwable error) {
                            Logger.log(LogType.ON_ERROR, error);
                        }
    
                        @Override
                        public void onComplete() {
                            Logger.log(LogType.ON_COMPLETE);
                        }
                    });
    
    
            TimeUtil.sleep(2000L);
        }
    }

     

    doAfterNext

    • 생산자가 통지한 데이터가 소비자에 전달된 직후 호출되는 함수입니다.

     

    doOnTerminate

    • 완료 또는 에러가 통지될 때 호출되는 함수입니다.
    • doOnComplete + doOnError

     

    doAfterTerminate

    • 완료 또는 에러가 통지된 후 호출되는 함수입니다.
    • after doOnComplete + doOnError

     

    doFinally

    • 구독이 취소된 후, 완료 또는 에러가 통지된 후 호출되는 함수입니다.
    • doOnDispose/doOnCancel + doOnComplete + doOnError

     

    doOnLifecycle

    • 소비자가 구독할 때 또는 구독 해지할 때 호출되는 함수입니다.
    • doOnSubscribe + doOnDispose/doOnCancel

     

     

     

    [참고 자료]

    반응형

    'BackEnd > RxJava' 카테고리의 다른 글

    테스트(2)  (0) 2023.07.16
    테스트(1)  (0) 2023.07.16
    스케쥴러(Scheduler)  (0) 2023.07.15
    Subject  (0) 2023.07.14
    집계 연산자  (0) 2023.07.13

    댓글

Designed by Tistory.