[Kotlin] RxKotlin Study 01

Reactive Prgramming in Kotlin

Posted by JungHoon-Park on February 2, 2021

RxKotlin 공부하기


리액티브 프로그래밍이란

코드를 보고 이해해 보자

1
2
3
4
5
6
7
8
9
fun main(args: Array<String>) {
    var number = 4
    var isEven = isEven(number)
    println("The Number is" + (if (isEven) "Even" else "Odd"))
    number = 9
    println("The Number is" + (if (isEven) "Even" else "Odd"))
}

fun isEven(num: Int): Boolean = ((n%2) == 0)


프로그램의 출력을 확인하면 number에 새로운 값이 할당되었음에도 isEven이 여전히 true라는 것을 알 수 있다.
그러나 isEvennumber 변수의 변경 사항을 추적하도록 설정됐다면 자동으로 false가 됐을 것이다.
바로 이것이 리액티브 프로그램의 동작이다.

함수형 리액티브 프로그래밍을 적용해야 하는 이유

  • 콜백 지옥의 제거
  • 오류 처리를 위한 표준 메커니즘
  • 간결해진 스레드 사용
  • 간단한 비동기 연산
  • 전체를 위한 하나, 모든 작업에 대해 동일한 API
  • 함수형 접근
  • 유지 보수 가능하고 테스트 가능한 코드

RxJava의 푸시 메커니즘과 풀 메커니즘 비교

RxKotlin 은 전통적인 프로그램에서 사용되는 Iterator 패턴의 풀 메커니즘 대신 푸시 메커니즘의 데이터/이벤트 시스템으로 대표되는 옵저버블 패턴을 중심으로 작동한다. 그렇기 때문에 지연 평가가 일어나며 동기식 또는 비동기식으로 모두 이용될 수 있다.

[예제를 보자]

1
2
3
4
5
6
7
fun main(args: Array<String>) {
    var list: List<Any> = listOf("One", 2, "Three", "Four", 4.5, "Five", 6.0f) //1
    var iterator = list.iterator() //2
    while(iterator.hasNext()) { //3
        println(iterator.next()) // 각 엘리먼트를 출력한다 4
    }
}


1 -> 주석에서는 7개 항목의 리스트를 생성한다.
2 -> 리스트로부터 iterator를 생성하는데, 이를 통해 데이터를 순회할 수 있다.
3 -> while 루프를 생성해 iterator의 도움으로 데이터를 당겨오고 있다.
4 -> 해당 값을 출력한다.

알아 둬야 할 점은 데이터가 수신돼 준비될 때까지 현재 스레드는 블로킹된 상태에서 리스트로부터 데이터를 당겨온다는 것이다.
예를 들어 단순한 리스트가 아니라 네트워크 호출이나 데이터베이스 쿼리를 사용해 데이터를 가져온다면 스레드가 얼마나 블로킹돼 있을지 생각해보자. 데이터 접근을 위해 프로그램이 데이터를 기다리게 만들어야할까? 데이터가 사용 가능해졌을 때 프로그램으로 데이터가 푸시돼야 할까?


ReactiveX 프레임워크의 주요 구성 요소는 옵저버블(Observable)이다.
Observable 클래스는 정확히 iterator 패턴의 반대에 위치한다. Observable 클래스에는 컨슈머가 소비할 수 있는 값을 생성하는 기본 컬렉션 또는 계산이 있다.
iterator 와의 차이점은 컨슈머가 이터레이터 패턴과 같이 프로듀서로부터 이런 값을 당겨오지 않는다는 점이다. 대신 프로듀서는 컨슈머에게 값을 알림으로 푸시한다.

[예제를 보자-1]

1
2
3
4
5
6
7
8
9
10
fun main(args: Array<String>) {
    var list: List<Any> = listOf("One", 2, "Three", "Four", 4.5, "Five", 6.0f)
    var observable: Observable<Any> = list.toObservable()

    observable.subscribeBy(
        onNext = { println(it) },
        onError = { it.printStackTrace() },
        onComplete = { println("Done!") }
    )
}


1 -> 리스트를 생성한다.
2 -> 1번에서 생성한 리스트로 observable 인스턴스를 생성한다.
3 -> observable 인스턴스를 구독한다.

observable을 구독했기 때문에 모든 변경 사항은 onNext로 푸시될 것이고 모든 데이터가 푸시됐을 때는 onComplete, 에러가 발생했을 때는 onError가 호출된다.

[예제를 보자-2]

1
2
3
4
5
6
7
8
fun main(args: Arrays<String>) {
    var subject:Subject<Int> = PublishSubject.create()
    subject.map({isEven(it)}).subscribe({
        println("The Number is ${(if (it) "Even" else "Odd")"})
    })
    subject.onNext(4)
    subject.onNext(9)
}


subject에 숫자를 통지하면 그것은 map 내의 메서드를 호출하고 차례대로 메서드의 반환값과 함께 subscribe 내의 함수가 호출된다. map에 사용된 메서드는 숫자가 짝수인지 검증하고 그에 따라 참, 거짓을 반환한다.
subscribe의 메서드에서는 해당 값을 입력받아 각각 even과 odd를 출력한다. subject.onNext 메서드는 새로운 값을 subject로 전달해 처리할 수 있다.


이 포스트를 통해 리액티브 프로그래밍이 무엇인지 알아보았다.