RxJava, RxAndroid 시작하기

안드로이드 개발을 하다보면 언젠가는 RxJava와 만나게 된다. 이미 몇 년 전부터 많은 프론트 개발자들이 사랑사용해 온 라이브러리이기 때문이다. 현재 회사 프로젝트에서는 통신이나 클릭 등의 비동기 처리를 할 때 부분적으로 Rx를 적용해서 사용하고 있다. 얼추 개념과 용어를 알겠고 얼추 기능을 사용할 수는 있지만, 스택오버플로우만 쫓아가다 보니 이게 왜, 어디에 사용되는 건지 불분명해서 이번 기회에 차근차근 공부해보려고 한다.


Rx, Reactive… 대체 뭘까…

‘RxJava란?’, ‘RxAndroid란?’ 을 이해하기 위해 개념 정의를 거슬러 올라가보자.

  • RxAndroid 는 RxJava에 안드로이드용 스케쥴러 등 몇 가지 클래스를 추가해 안드로이드 개발을 쉽게 해주는 라이브러리이다.

  • RxJava 는 ReactiveX(Reactive Extensions)를 Java로 구현한 라이브러리이다.

  • ReactiveX 는 관찰 가능한(Observable) 스트림을 사용하는 비동기 프로그래밍을 위한 API이다.
    (공홈 헤드 문구이다. - An API for asynchronous programming with observable streams.)

  • Reactive Programming 은 데이터 흐름과 변화의 전파와 관련있는 선언적 프로그래밍 패러다임이다.
    (위키백과 출처라 그런지 설명이 너무 어렵다. - Reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change)


RxJava도, 상위 개념들도 모두 한 문장으로 정의내리기엔 개념이 어렵다. 반응형 프로그래밍이란 대체 무엇이길래 ReactiveX와 RxJava, RxAndroid 등을 만드는 배경이 되었을까.

반응형 프로그래밍(Reactive Programming) 를 다시 말해보면 주변 환경과 끊임없이 상호 작용을 하는 프로그래밍 을 의미한다. 환경이 변화면 이벤트를 받아 동작하도록 만드는 프로그래밍 기법이다. 그럼 기존에는 주변 환경과 상호 작용을 하지 않았을까? 여기 간단한 예시가 있다.

기존의 명령형 프로그래밍에서는 a=b+c 에서 a는 b+c의 연산이 끝난 이후에 그 결과를 통해 값이 할당될 것이다. 만약 이후에 b나 c의 값이 변하더라도 a에는 영향을 주지 않기 때문에 문제가 생길 수 있다. 반면 리액티브 프로그래밍에서는 b나 c의 값이 변동되더라도 b+c 연산을 다시 할 필요 없이 자동으로 업데이트된다.

이제 반응형 프로그래밍에서는 데이터가 변하면 알아서 캐치해서 반영한다는 것은 알겠다. 하지만 구체적으로 어떻게 돌아가는 것인지 궁금해진다. 이에 대한 궁금증을 풀기 위해 명령형 프로그래밍 방식과의 차이를 조금 더 딮하게 비교해보자.


명령형 프로그래밍과 반응형 프로그래밍의 차이

명령형 프로그래밍 (Imperative programming)

명령형 프로그래밍은 작성된 코드가 정해진 순서대로 실행되는 방식의 프로그래밍이다. 코드가 순서대로 진행되므로 이해하기 쉽다. 즉 개발자가 작성한 조건문, 반복문, 함수를 따라 컴파일러가 다른 코드로 이동하게 된다.

짝수만 출력하도록 만들어진 아래 예제를 살펴보자.

public void imperativeProgramming() {
    ArrayList<Integer> items = new ArrayList<>();
    items.add(1);
    items.add(2);
    items.add(3);
    items.add(4);

    for (Integer item : items) {
        if (item % 2 == 0) {
            System.out.println(item);
        }
    }

    items.add(5);
    items.add(6);
    items.add(7);
    items.add(8);
}
// Result
2
4


위의 코드는 다음과 같이 작동한다.

  1. 리스트를 만든다.
  2. 리스트에 1~4 아이템을 추가한다.
  3. for문으로 items 리스트를 순회하며 짝수를 출력한다.
  4. 리스트에 5~8 아이템을 추가한다.

println() 이후에 리스트에 아이템을 추가해도 결과에는 영향을 미치지 않는다.


반응형 프로그래밍(Reactive Programming)

반응형 프로그래밍은 시간 순으로 들어오는 모든 데이터의 흐름을 스트림(Stream) 으로 처리하며, 하나의 데이터 흐름은 다른 데이터 흐름으로 변형되기도 하고, 여러 데이터 흐름이 하나의 데이터 흐름으로 변경될 수도 있다.

마찬가지로 짝수만 출력하도록 만들어진 예제를 살펴보자.

public void reactiveProgramming() {
    PublishSubject<Integer> items = PublishSubject.create();
    items.onNext(1);
    items.onNext(2);
    items.onNext(3);
    items.onNext(4);

    items.filter(item -> item % 2 == 0)
            .subscribe(System.out::println);

    items.onNext(5);
    items.onNext(6);
    items.onNext(7);
    items.onNext(8);
}
// Result
6
8


위의 코드는 다음과 같이 작동한다.

  1. 데이터 스트림을 만든다. (PublishSubject)
  2. 데이터 스트림에 1~4 아이템을 추가한다.
  3. 데이터 스트림에서 짝수만 출력하는 데이터 스트림으로 변형한 뒤 구독한다.
  4. 데이터 스트림에 5~8 아이템을 추가한다.

PublishSubject 는 구독 시점 이후의 데이터만 옵저버에 전달하기 때문에 6, 8만 출력된다. (구독시점 이전의 데이터까지 출력하려면 ReplaySubject로 대체할 수 있다.)


그래서, RxJava는?

다시 읽어보면 ‘관찰 가능한’ 스트림을 사용한다는 이야기가 조금은 이해가 간다. RxJava는 개발자들이 직면하는 문제들- 예를 들어 동시성 문제, 다중 이벤트 처리, 백그라운드 처리 등의 문제를 아름답게 해결할 수 있도록 도와준다. 안드로이드 개발의 경우 화면(UI)을 변경할 수 있는 것은 메인 쓰레드 뿐이기 때문에 비동기 처리를 하는 일이 빈번하다. Rx를 이용하면, 어렵고 실패 확률이 높았던 이런 작업들을 쉽게 할 수 있다. 또, 새로운 프로세스가 추가되어거나 삭제되어야 한다면 로직의 큰 변경 없이 간단히 수정할 수 있다.


안드로이드 프로젝트에 Rx 적용하기

안드로이드에 RxJava를 적용하려면 build.gradle에 추가해주어야 한다. 2020년 10월 11일 기준 RxAndroid는 3.0.0, RxJava는 3.0.7 버전이 최신 버전이다.

https://github.com/ReactiveX/RxJava

dependencies {
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'io.reactivex.rxjava3:rxjava:3.0.7'
}


RxJava가 어떤 역할을 하는지, 안드로이드 개발에서 어떤 역할을 할지 감이 온다. 다음 포스트에서는 RxJava의 핵심 개념인 Observable 에 대해 알아보겠다.


References

  • 옥수환, 『아키텍처를 알아야 앱 개발이 보인다』, 비제이퍼블릭(2020)
  • https://en.wikipedia.org/wiki/Reactive_programming