본문 바로가기
Rx

리액티브연산자[생성연산자]-10(defer함수)

by 봄석 2018. 12. 26.

본 내용은 필자가 학습한 내용을 정리하는 내용입니다.

대부분 의 내용이 아래 책의 내용이므로 원서를 구매해서 직접보시는걸 추천드립니다!

RxJava 프로그래밍 리액티브 프로그래밍 기초부터 RxAndroid까지 한 번에

유동환 , 박정준 지음 | 한빛미디어 | 2017년 09월 04일 출간

http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788968488658&orderClick=LAV&Kc=


저자님의 블로그

https://brunch.co.kr/@yudong#info




리액티브 연산자(함수) 분류 - 카테고리

연산자 종류 

연산자 함수 

  생성 연산자 


 just(), fromXXX(), create(), interval(), ragne(), timer(),   intervalRange(), defer(), repeat() 


  변환 연산자


 map(),flatMap(), concatMap(), switchMap() , groupBy(),

 scan(), buffer(), window()


  필터 연산자


 filter(), take(), skip(), distinct()


  결합 연산자

 

 zip(), combineLatest(), merge(), concat()

 

  조건 연산자


 amb(), takeUtil(), skipUtil(), all()

 

  에러 처리 연산자 


 onErrorReturn(), onErrorResumeNext(), retry(), retryUntil()


  기타 연산자 

 

 subscribe(), subscribeOn(), observeOn(), reduce(), count()

 




생성연산자- defer()함수

defer() 함수는 timer() 함수와 비슷하지만 데이터 흐름 생성을 구독자가 subscribe() 함수를 호출할 때 까지 미룰 수 있습니다. 이때 새로운 Observable이 생성됩니다.


defer() 함수의 마블다이어그램

출처 - http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html


Observable의 생성이 구독할 때 까지 미루어 지기 때문에 최신 데이터를 얻을 수 있습니다.

마블 다이터 그램을 보면 첫번째 구독자는 빨간색의 도형들을 수신하고 두번째 구독자는 초록색의 도형들을 수신합니다 .


defer() 함수의 원형은 다음과 같습니다.

@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> defer(
Callable<? extends Observable<? extends T>> supplier){ }

스케줄러가 '없음(NONE)' 이기 때문에 현재스레드에서 실행되며 실행인자로는 Callable<Observable <T>>를 받습니다. Callable 객체이므로 구독자가 subscribe() 를 호출할 때 까지 call() 메소드 호출을 미룰 수 있습니다 .


defer() 함수의 활용 예

Iterator<String> colors=Arrays.asList("1","3","5","6").iterator();
    
    public void marbleDiagram() { 
        Callable<Observable<String>> supplier = () -> getObservable();        
        Observable<String> source = Observable.defer(supplier);
        
        source.subscribe(val -> Log.i("Subscriber #1:" + val));
        source.subscribe(val -> Log.i("Subscriber #2:" + val));
        CommonUtils.exampleComplete();
    }
 
    //번호가 적인 도형을 발행하는 Observable을 생성합니다.
    private Observable<String> getObservable() { 
        if (colors.hasNext()) { 
            String color = colors.next();
            return Observable.just(
                Shape.getString(color, Shape.BALL), 
                Shape.getString(color, Shape.RECTANGLE), 
                Shape.getString(color, Shape.PENTAGON));             
        }
        
        return Observable.empty();        
    }



Colors 변수는 도형의 색상을 담은 리스트입니다. 별도 인덱스 변수를 만들지 않고 차례로 가져오기위해 iterator() 함수(반복자)를 활용했습니다. 핵심 메소드는 get Observable()이고 

이 메소드는 현재 색상을 가져와서 몇 개의 도형을 발행합니다. 다음 색상이 없는 경우 빈 Observable을 발행합니다. 


defer() 함수를 활용하는 마블 다이터 그램의 예제는 marbleDiagram() 메소드에서 시작합니다.

이 메소드에는 Callable<Observable<String>> 타입의 supplier 변수에 람다 표현식을 활용하여 getObservable() 메소드를 호출합니다. 그 다음은 Observable을 생성하여, defer() 함수에 넣고 구독자를 1명씩 추가합니다.

실행결과는 아래와 같습니다.

main | value = Subscriber #1:1
main | value = Subscriber #1:1-R
main | value = Subscriber #1:1-P
main | value = Subscriber #2:3
main | value = Subscriber #2:3-R

main | value = Subscriber #2:3-P

위 예제는 모두 main스레드에서 실행되었습니다. 마블다이어그램처럼 첫 번째 구독자는 '1'도형(빨간색 도형)을 수신했고,두 번째 구독자는 '3'도형(초록색도형)을 수신했습니다.


그럼 defer() 함수를 활용하지 않고 getObservable 메소드에 반환하는 Observable을 그대로 구독하면 어떻게 될까요 ?


getObservable()에서 반환하는 Ovservable 그냥 구독

Observable<String> source=getObservable();
source.subscribe(var->Log.i("Subscriber #1 :"+var));

 source.subscribe(var->Log.i("Subscriber #2 :"+var));


실행결과


main | value = Subscriber #1 :5
main | value = Subscriber #1 :5-R
main | value = Subscriber #1 :5-P
main | value = Subscriber #2 :5
main | value = Subscriber #2 :5-R
main | value = Subscriber #2 :5-P



구독자가 달려져도 동일하게 '5'를 출력합니다.


여기서 다룬 Observable은 모두 차가운 Observable 입니다. Observable을 생성할 때 입력값이 결정되고 구독자가 subscribe()함수를 호출하면 그때 해당 데이터 흐름을 그대로 발행합니다. 

즉, defer() 함수를 활용하면 subscribe() 함수를 호출할 때의 상황을 반영하여 데이터 흐름의 생성을 지연하는 효과를 보여줍니다. 내부적으로 구독자가 subscribe()를 호출하면 그때 supplier의 call() 메소드를 호출합니다.

댓글