본문 바로가기

Android 공부/rxJava 공부

RxJava 공부 3 - Map과 FlatMap, Timer와 interval, FlatMap과 ConcatMap

-1. 이전글


2018/12/10 - [rxJava 공부] - RxJava 공부 1 - just, create, fromArray, interval, range, fromIterable, filter, map

2018/12/10 - [rxJava 공부] - RxJava 공부 2 - AsyncSubject, BehaviorSubject, PublishSubject, ReplaySubject

0. 출처


http://reactivex.io/documentation/ko/operators.html


1. Map & FlatMap


  • Map — Observable이 배출한 항목에 함수를 적용한다
  • FlatMap — 하나의 Observable이 발행하는 항목들을 여러개의 Observable로 변환하고, 항목들의 배출을 차례차례 줄 세워 하나의 Observable로 전달한다


1-1. 코드:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MainActivity : AppCompatActivity() {
    var count = 0
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //val myObserver = MyObserver(this, lifecycle)
        setContentView(R.layout.activity_main)
        executeFlatMap(arrayListOf("0""1""2""3"))
    }
 
    //FlatMap은 보시는 바와 같이 Observable 객체를 만들어서 받은 데이터를 가공하는 것이고
    //Map은 단순하게 데이터를 받아서 데이터로 가공하는 것을 말한다.
    private fun executeFlatMap(datas: List<String>= Observable.fromIterable(datas)
            .flatMap { data ->
                Observable.just(data).map { data -> "$data*$data" }
            }.subscribe { justData -> Log.d("data:", justData) }
}
cs


1-2. 결과:



1-3. 해석:


Map과 FlatMap은 둘 다 모두 받은 데이터를 가공하기 위해서 사용하는 함수이다.

하지만 둘의 차이점은 Map은 단순하게 함수로 받은 데이터를 데이터로만 가공하는 것이라면

FlatMap은 함수로 받은 데이터를 RxJava의 Observable과 관련된 함수를 통해서 다시 재사용할 수 있는 것을 의미한다.



2. Timer & interval & take


  • Timer — 지정된 시간이 지나고 난 후 항목을 하나 배출하는 Observable을 생성한다
  • Interval — 특정 시간별로 연속된 정수형을 배출하는 Observable을 생성한다
  • Take — Observable이 배츨한 처음 n개의 항목들만 배출한다

2-1. 코드 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MainActivity : AppCompatActivity() {
    var count = 0
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //val myObserver = MyObserver(this, lifecycle)
        setContentView(R.layout.activity_main)
        executeInterval()
        executeTimer()
    }
 
    //0초 후에, 1초마다 take만큼 실행
    private fun executeInterval()=Observable.interval(0,1,TimeUnit.SECONDS)
            .take(5).subscribe{count->Log.d("count1#",count.toString())}
 
    //10초후에 1번 실행
    //take가 있음에도 불구하고 timer는 특정 시간 후에 한 번만 실행 됨.
    private fun executeTimer()=Observable.timer(10,TimeUnit.SECONDS)
            .take(5).subscribe{count->Log.d("count2#",count.toString())}
    
}
cs

2-2. 결과:

2-3. 해석:

take() : n번 실행한다는 의미로 사용되는 함수이다.

interval(): 특정 주기마다 실행되는 함수이다.

timer(): 특정 시간 휑 1번만 실행되는 함수이다.


3. FlatMap & ConcatMap


  • FlatMap — 하나의 Observable이 발행하는 항목들을 여러개의 Observable로 변환하고, 항목들의 배출을 차례차례 줄 세워 하나의 Observable로 전달한다. 하지만, 순서를 보장하지 않는다.
  • ConcatMap — FlatMap과 다르게 차례차례 줄을 세우지만, 순서를 보장한다.

3-1. 코드:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class MainActivity : AppCompatActivity() {
    var count = 0
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //val myObserver = MyObserver(this, lifecycle)
        setContentView(R.layout.activity_main)
        val datas = arrayListOf<String>("data1","data2","data3","data4","data5")
        executeFlatMapForCompare()
        executeConcatMapForCompare()
    }
 
    //flatMap은 interleaving이 허용되어
    //데이터의 순서가 보장되지 않는다.
    //1초마다 5번실행하는 flatMap
    //flatMap을 통해서 Obervable.interval이 다시 실행되고
    //1초마다 5번 실행된다. 그리고 상위 take의 count와 하위 take의 count를 출력한다.
    //subsribe를 통해서 로그를 찍는다.
    //Observable의 take가 실행된다.
    //flatMap의 take가 실행된다.
    //하지만 병렬적인 느낌으로 flatMap.take(5)로 5번 실행되기도 전에 Observable.interval.take(5)가 실행된다.
    //결국 5초 정도로 순서가 허용되지 않고 데이터를 출력해버린다.
    private fun executeFlatMapForCompare() = Observable
            .interval(01, TimeUnit.SECONDS)
            .take(5)
            .flatMap { index -> Observable.interval(0,1,TimeUnit.SECONDS).take(5).map { m-> "flat_index:$index $m"}}
            .subscribe { updateData -> Log.d("flat#", updateData) }
 
    //concatMap은 interleaving이 불허용되어
    //데이터의 순서가 보장된다.
    //1초마다 5번실행하는 flatMap
    //flatMap을 통해서 Obervable.interval이 다시 실행되고
    //1초마다 5번 실행된다. 그리고 상위 take의 count와 하위 take의 count를 출력한다.
    //subsribe를 통해서 로그를 찍는다.
    //Observable의 interval이 실행된다.
    //concatMap의 Observable의 interval이 5번 실행된다.
    //상위의 Observable은 concatMap이 끝나지 않았으므로
    //계속해서 concatMap의 take가 끝날 때까지 출력한다.
    //상위의 Observable 5번과 concatMap의 5번이 실행된다.
    //5*5..
    private fun executeConcatMapForCompare() = Observable
            .interval(01, TimeUnit.SECONDS)
            .take(5)
            .concatMap { index -> Observable.interval(01, TimeUnit.SECONDS).take(5).map { m -> "concat_index:$index $m"} }
            .subscribe { index -> Log.d("concat#", index) }
}
cs


3-2. 결과:



3-3. 해석


flatMap은 보이는 것처럼 00초에서 07초까지 순서가 보장되지 않고 막 실행되다가 끝난다.

결국 상위의 take5번과 하위의 take5번은 병렬적인 느낌으로 실행되버린다.

그리고 또한 데이터의 순서를 보장받지 못 한다.


concatMap은

2018-12-10 16:30:19.315 21344-21418/hbs.com.studyandroidach D/concat#: concat_index:4 4 까지 실행된다.

index의 순서로 생각했을 때 0 0 ~ 4 4 까지 순서대로 실행되기 때문에

데이터의 순서를 보장받을 수 있다.