Subject

  • 차가운 옵저버블을 뜨거운 옵저버블로 변환해주는 클래스이다.
  • 옵저버블과 옵저버의 역할을 모두 수행할 수 있다.
  • 같은 동작의 옵저버블을 모아서 관리할 수 있다.
  • 마음대로 원하는 시점에 값을 발행할 수 있기 때문에 특히 원하는 데이터가 옵저버블이 아닐 때 편하게 사용 가능하다.

PublishSubject

  • 가장 평범한 Subject 클래스이다.
  • 발생한 값을 그대로 구독자들에게 전달한다.
  • subscribe() 이후 데이터 값 발행을 시작한다.

PublishSubject<String> publishSubject = PublishSubject.create();
    publishSubject.subscribe(System.out::println);

    publishSubject.onNext("apple");
    publishSubject.onNext("banana");

  • ex) 홈 - 리로드

PublishSubject<Boolean> reload = PublishSubject.create();
reload.subscribe(
    v -> {
        fetch();
        sync();
    }
);

Observable<Boolean> networkConnected = Observable.just(true);
networkConnected.subscribe(reload);

public void tapReloadButton() {
    reload.onNext(true);
}

BehaviorSubject

  • 기본값을 가지는 서브젝트이다. 생성할 때도 기본값을 넣어준다.
  • 구독 시점에 바로 최근의 값을 넘겨준다.
  • onComplete에 따로 넘겨주는 값은 없다.

BehaviorSubject<String> behaviorSubject = BehaviorSubject.createDefault("Default");
behaviorSubject.subscribe(System.out::println); // "Default"
behaviorSubject.onNext("Next"); // "Next"
behaviorSubject.subscribe(System.out::println); // "Next"
String value = behaviorSubject.getValue(); // Next;

  • ex) 퀵메뉴 - 운동

BehaviorSubject<ExerciseIntensity> intensity = BehaviorSubject.createDefault(ExerciseIntensity.none);
intensity.subscribe(
    v -> {
        // draw - textView.setText(v);
    }
);

// 팝업을 열었을 때 이전값 선택되어야 함
showPopUpView(value: intensity.getValue());

// 확인 버튼 탭하면 호출
public void popupCompletion(value: ExerciseIntensity) {
    intensity.onNext(value);
}

AsyncSubject

  • onComplete이 되면 옵저버블에서 발행한 가장 마지막 데이터만을 얻어온다.
  • 이전 데이터는 무시된다.

AsyncSubject<String> asyncSubject = AsyncSubject.create();
asyncSubject.subscribe(System.out::println);
asyncSubject.onNext("1");
asyncSubject.onNext("2");
asyncSubject.onNext("3");
asyncSubject.onComplete(); // 3

ReplaySubject

  • 구독자가 새로 생기면 데이터의 처음부터 끝까지 다시 발행해 준다.
  • 메모리 낭비가 일어날 수 있다.

ReplaySubject<String> replaySubject = ReplaySubject.create();
replaySubject.onNext("1");
replaySubject.onNext("2");
replaySubject.onNext("3");
replaySubject.subscribe(System.out::println); // 1, 2, 3

ConnectableObservable 클래스

  • 데이터 하나를 여러 구독자에게 공유할 때 사용한다.
  • 첫 데이터 방출을 유예시킬 수 있다.

ConnectableObservable<String> connectableObservable = publishSubject.publish(); // 변환
connectableObservable.subscribe(System.out::println); // 구독 1
connectableObservable.subscribe(System.out::println); // 구독 2
publishSubject.onNext("1"); // 아무 일도 일어나지 않음
connectableObservable.connect(); // 이때부터 값 방출 시작(사실상 구독 시작)
publishSubject.onNext("2"); // 2, 2

map 함수

  • 입력값을 넣어서 원하는 값으로 변환하는 함수이다.
  • Function<이전타입, 다음타입> 객체를 인자로 받기 때문에 람다식을 바로 활용하거나 구현해 넣어줄 수 있다.
  • Function 타입은 java.util.function.Function가 아니라 io.reactivex.functions.Function에서 임포트해야 한다.

// 람다식으로 적용
String[] balls = {"1", "2", "3", "4"};
Observable<String> source = Observable.fromArray(balls)
        .map(ball -> ball + "<>");

source.subscribe(System.out::println); // 1<> 2<> 3<> 4<>

// 선언 및 적용
Function<String, Integer> makeInteger =
        ball -> Integer.parseInt(ball);

Observable.fromArray(balls)
        .map(makeInteger)
        .subscribe(System.out::println); // (Integer) 1 2 3 4