[RxAndroid] RxAndroid Basic: Part2

RxAndroid Basic: Part2

Part1에서는

에 대해서 알아봤습니다.

이제 좀 더 응용 버전의 Observable과 Operators 예제들을 살표보도록 하겠습니다.

Example 4: Subjects

예제 설명

예제 보기 전에 또 하나의 RxJava Concept : Subject

Subject

Subject은 Event를 전달 받아 Observer들에게 Event를 전파하는 중간 다리로 볼 수 있습니다.

Android에서는 EventBus와 같은 형태로 사용이 가능합니다.

Subject은 여러 타입이 있는데 여기서는 그 중에서 가장 간단한 PublishSubject를 사용함

With PublishSubject

이제 그 반대쪽으로 나오는 결과를 후킹을 하려고 함

Subject은 Observable이기 때문에 Observe할 수 있음.

이를 이용해서 pip의 반대쪽 끝에서 나오는 결과를 지켜보는 것이 가능함

mCounterEmitter = PublishSubject.create();
mCounterEmitter.subscribe(new Observer<Integer>() {
  
  @Override
  public void onCompleted() {}
  
  @Override
  public void onError(Throwable e) {}
  
  @Override
  public void onNext(Integer integer) {
    mCounterDisplay.setText(String.valueOf(integer));
  }
});

PublishSubject는 value를 어떻게 발행하나?

mIncrementButton.setOnClickListener(new View.OnClickListener() {

    @Override 
    public void onClick(View v) { 
        mCounter++;
        mCounterEmitter.onNext(mCounter);
    }
});

mIncrementButton 두 가지 일을 함

  1. mCounter 값을 증가시킴
  2. mCounterEmitter(PublishSubject)의 onNext() 메서드를 호출함

Subjects은 Observer이기도 하기 때문에 onNext() 메서드를 가짐

즉, 위의 예제들은 아래와 같은 흐름으로 실행됨

  1. Subject의 onNext() 메서드를 호출해 pipe의 한 쪽 끝으로 mCounter를 집어 넣음
  2. Subject은 onNext() 메서드를 통해 들어온 mCounter를 value로 발행함
  3. Subject을 subscribe하고 있던 Observer는 value로 발행된 mCounter를 onNext 콜백으로 받음

이런 특징을 이용하면 EventBus처럼 Activity나 앱의 Lifecycle과 동일하게 살아있도록 해서 Event를 전파하는 역할로 사용할 수 있음

Example 5: Map()

예제 설명

새로운 RxJava Concept: map

map

데이터 가공 Map

Operator

Value 4를 발행하는 Single 예제

Single.just(4).map(new Func1<Integer, String>() { 
    
    @Override 
    public String call(Integer integer) { 
        return String.valueOf(integer);
    } 
}).subscribe(new SingleSubscriber<String>() { 
    
    @Override 
    public void onSuccess(String value) { 
        mValueDisplay.setText(value); 
    } 
    
    @Override 
    public void onError(Throwable error) { } 
});

숫자 4가 발행되지만 text로 표시해야 되기 때문에 map을 이용해서 Interger 4를 String로 변환해서 전달함

Observable에서 발행한 데이터를 받아서 변환 또는 추가 로직을 수행해서 다시 Observable로 반환

Example 6: Bringing it All Together

예제 설명

지금까지 배운거 다 동원한 mega-example

New RxJava Concept: debounce

debounce

자, 시작해봅시다.

mTextWatchSubscription = mSearchResultsSubject
  .debounce(400, TimeUnit.MILLISECONDS)
  .observeOn(Schedulers.io())
  .map(new Func1<String, List<String>() {
    
    @Override
    public List<String> call(String s) {
      return mRestClient.searchForCity(s);
    }
  })
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Observer<List<String>>() {
    
    @Override
    public void onCompleted() {}
    
    @Override
    public void onError(Throwable e) {}
    
    @Override
    public void onNext(List<String> cities) {
      handleSearchResults(cities);
    }
  });

mSearchInput.addTextChangedListener(new TextWatcher() {
  
  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
  
  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
    mSearchResultsSubject.onNext(s.toString())
  }
  
  @Override
  public void afterTextChanged(Editable s) {}
});

위의 예제에서 TextWatcher는 사용자가 키보드를 입력할 때마다 onTextChanged 발생하고, mSearchResultsSubject의 onNext가 불려서 사용자가 입력한 값이 발행되도록 되어 있음. 하지만, 사용자가 키보드를 입력할 때마다 value를 발행해서 해당 value로 서버에 요청을 보내는 것은 바람직하지도 않고, 원하는 바도 아님.

즉, 우리가 원하는 것은 일정 시간 이상 사용자가 입력이 없을 때만 사용자가 지금까지 입력한 값으로 서버에 요청하는 것임

이를 가능하게 하는 것이 debounce()임

위의 예제에서는 400ms동안 사용자의 입력이 없으면, 입력 값으로 서버에 요청함

.observeOn(Schedulers.io())

.map

.observeOn(AndroidSchedulers.mainThread())

.subscribe

mSearchResultsSubject 
         |
         |
         V
      debounce
        ||| 
        |||
         V 
        map 
         | 
         | 
         V
      observer

마치며

RxJava의 가장 기본적인 concept과 몇 개의 예제를 살펴봤음

RxJava에는 이밖에도 아주 많은 Operator들이 있기 때문에 다양한 응용을 위해서는 추가로 살펴볼 것을 추천함

아직 RxJava의 기본 컨셉을 이해한 수준이지만, 이번 Part1에서 언급한 장점만으로도 충분히 안드로이드 앱 개발자에게 매력적으로 느껴질 수 있는 라이브리러가 아닌가 하는 생각이 듭니다.