RxAndroid로 리액티브 앱 만들기 #4

  1. RxAndroid로 리액티브 앱 만들기 #1
  2. RxAndroid로 리액티브 앱 만들기 #2
  3. RxAndroid로 리액티브 앱 만들기 #3
  4. RxAndroid로 리액티브 앱 만들기 #4

RxAndroid 시리즈의 마지막 글 입니다. 이번 시간에는 스케쥴러를 이용하는 법과 Retrofit, Realm 등의 다른 라이브러리와 함께 쓰일 때 어떻게 쓰일 수 있을지를 살펴보겠습니다.

스케쥴러

스케쥴러는 해당 옵저버블, 오퍼레이터, 서브스크라이버를 어떤 스레드에서 수행할지 결정하는 것입니다. 스케줄러가 어떤 부분을 맞게 되는지는 subscribeOnobserveOn으로 지정합니다. 아래의 그림을 함께 봅시다.

이미치 출처 : http://reactivex.io/documentation/operators/observeon.html


observeOn에서 지정한 스케쥴러는 이후에 따라오는 오퍼레이터, 서브스크라이버에 적용된 것을 볼 수 있습니다. 두번의 observeOn에 의해 첫번째는 주황색 스케쥴러로 지정이 되어 모든 라인이 주황색으로 색칠이 되어 있고 두번째는 핑크색으로 스케쥴러를 지정한 것을 볼 수 있다.

이런 개발 뉴스를 더 만나보세요

subscribeOn은 옵저버블의 스케쥴러를 바꾸는 것입니다. 옵저버블을 파란색으로 지정한 것을 볼 수 있습니다.

스케쥴러 목록

스케쥴러는 RxJava가 제공하는 스케쥴러와 RxAndroid가 제공하는 스케쥴러가 있습니다. 먼저 RxJava가 제공하는 스케쥴러를 살펴봅시다.

  • Schedulers.computation() - 이벤트 룹에서 간단한 연산이나 콜백 처리를 위해서 쓰는 것입니다. I/O 처리를 여기에서 해서는 안됩니다.
  • Schedulers.from(executor) - 특정 executor를 스케쥴러로 사용합니다.
  • Schedulers.immediate() - 현재 스레드에서 즉시 수행합니다.
  • Schedulers.io() - 동기 I/O를 별도로 처리시켜 비동기 효율을 얻기 위한 스케줄러입니다. 자체적인 스레드 풀에 의존합니다.
  • Schedulers.newThread() - 항상 새로운 스레드를 만드는 스케쥴러입니다.
  • Schedulers.trampoline() - 큐에 있는 일이 끝나면 이어서 현재 스레드에서 수행하는 스케쥴러.

일부 오퍼레이터들은 자체적으로 어떤 스케쥴러를 사용할지 지정합니다. 예를 들어 buffer 오퍼레이터는 Schedulers.computation()에 의존하며 repeatSchedulers.trampoline()를 사용합니다.

RxAndroid는 아래와 같은 스케쥴러를 추가합니다.

  • AndroidSchedulers.mainThread() - 안드로이드의 UI 스레드에서 동작합니다.
  • HandlerScheduler.from(handler) - 특정 핸들러 handler에 의존하여 동작합니다.

안드로이드에 특화된 스케쥴러입니다. 보통은 RxAndroid가 제공하는 AndroidSchedulers.mainThread()와 RxJava가 제공하는 Schedulers.io()를 조합해서 Schedulers.io()에서 수행한 결과를 AndroidSchedulers.mainThread()에서 받아 UI에 반영하는 패턴등이 일반적으로 쓰입니다.

독립적으로 사용 가능한 스케쥴러

스케쥴러는 옵저버블, 오퍼레이터, 서브스크라이브 모델 밖에서 별도로 사용할 수 있습니다.

worker = Schedulers.newThread().createWorker();
worker.schedule(new Action0() {

    @Override
    public void call() {
        realmJob();
    }

});

realmJob은 새로운 스레드에서 수행됩니다.

Retrofit에서의 응용

스퀘어의 인기 라이브러리 Retrofit도 RxAndroid를 지원합니다.

먼저 그래들 설정에 의존성을 추가합시다.

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta3'
compile 'io.reactivex:rxandroid:1.1.0'

RxAndroid를 Retrofit이 다룰 수 있게 하기 위해 RxJavaCallAdapterFactory를 콜 어댑터 팩토리로 추가합니다.

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://realm.io/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

간단한 API를 통해 일반 버전과 Rx를 쓰는 버전의 차이를 살펴봅시다.

public interface RealmAPI {
    @GET("user")
    Call<User> getUser();

    @GET("user")
    Observable<User> getUserRx();
}

일반 버전인 getUser는 콜백인 Call<User>를 반환하고 Rx 버전은 Observable<User>를 반환하여 이제는 익숙해진 Rx 방식으로 다룰 수 있습니다.

Realm에서 활용

Realm에서 Rx를 쓰는 것도 간단합니다.

Realm realm = Realm.getDefaultInstance();
RealmResults<Person> persons = realm.where(Person.class).findAll();
Person person = persons.first();

Observable<Realm> realmObservable = realm.asObservable();
Observable<RealmResults<Person>> resultsObservable = persons.asObservable();
Observable<Person> objectObservable = person.asObservable();

비동기 API에서도 사용할 수 있습니다.

realm.where(Person.class).equalTo("name", "John").findAllAsync().asObservable()
  .filter(new Func1<RealmResults<Person>, Boolean>() {
      @Override
      public Boolean call(RealmResults<Person> persons) {
          // Ignore unloaded results
          return persons.isLoaded();
      }
  })
  .subscribe(new Action1<RealmResults<Person>>() {
      @Override
      public void call(RealmResults<Person> persons) {
          // Show persons...
      }
  });

마무리

기존의 자바 스크립트 라이브러리들은 비동기 처리가 필요한 경우 개별적인 API와 단순한 가공 정도를 제공했으나 Rx를 지원하는 현대적인 라이브러리에서는 다양한 방법으로 가공하여 사용할 수 있습니다. Retrofit이나 Realm도 그 중의 하나이고요.

앞으로 더 다양한 곳에서 더 멋진 방법으로 Rx를 사용해보세요.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Leonardo YongUk Kim

Leonardo YongUk Kim is a software developer with extensive experience in mobile and embedded projects, including: several WIPI modules (Korean mobile platform based on Nucleus RTOS), iOS projects, a scene graph engine for Android, an Android tablet, a client utility for black boxes, and some mini games using Cocos2d-x.

4 design patterns for a RESTless mobile integration »

close