본문 바로가기

코틀린

Kotlin Flow #3 - Zip And Combine

반응형

Rx에서 zip이나 combineLatest 등으로 여러 응답을 결합하여 사용하듯이,
코틀린에서도 여러 개의 Flow를 결합하여 사용할 수 있는 함수를 제공한다.

Flow 함께 사용하기

1. Zip

val nums = (1 .. 3).asFlow()
val strs = flowOf("one", "two", "three", "four").onEach {
    delay(1000)
    println("str")
}
nums.zip(strs) { a, b -> "$a -> $b" }.collect{
    delay(1000)
    println(it)
}

result :
1 -> one
2 -> two
3 -> three

첫 번째 방법으로 zip 을 이용할 수 있다.

 

zip 은 결합된 모든 Flow 가 데이터를 방출하기를 기다리고

모든 Flow가 하나씩 방출이 완료되어서 한쌍이 나오는 시점에서 결합 데이터를 방출한다.

 

Flow 중에 하나라도 방출과 사용이 완료가 되면 나머지 Flow는 자동으로 종료된다.

( 모든 데이터를 방출하려면 개수의 쌍이 맞아야 한다. )

 

위 예제를 보면 nums 가 "3"을 방출하고 사용이 끝난 시점에서

strs의 "four"가 남아있음에도 더 이상 출력이 없는 것을 확인할 수 있다.

 

zip 은 최대 두 개까지의 Flow 만 결합 할 수 있다.

first.zip(second) { a, b -> a to b }
    .zip(third) { (a, b), c ->
        transform(a, b, c)
    }

여러 개의 Flow를 zip 으로 연결하기 위해서 위와 같이

결과물의 다시 zip 으로 연결하는 방법을 사용하여야 한다.

2. Combine

val nums = (1..3).asFlow().onEach { delay(300) }
val strs = flowOf("one", "two", "three").onEach { delay(100) }

nums.combine(strs) { a, b -> "$a -> $b" }.collect {
    println(it)
}

result :
1 -> two
1 -> three
2 -> three
3 -> three

두 번째 방법으로는 combine 을 사용할 수 있다.


zip 과 다른 점 은 최신 데이터만 결합하여 방출하며,

모든 Flow 모두 완료될 때까지 멈추지 않고 동작한다.

 

모든 Flow 가 최소 하나의 데이터를 방출한 경우에 첫 번째 결합 데이터가 방출되고,

이후로는 어느 Flow 라도 데이터를 방출하면 모든 Flow의 최신 데이터를 결합하여 방출해준다.

 

위의 예제를 보면 "1", "two" 이 나온 시점이 최소 하나씩 데이터가 방출된 시점이고,

그 이후로는 하나라도 방출되면 출력이 발생하는 것을 확인할 수 있다.

combine(nums, strs){ num, str ->
  "$num $str"
}.collect { ... }

combine(listOf(nums, nums, nums, nums, nums, strs, strs)) {
    it.reduce { a, b -> "$a $b"}
}.collect { ... }

combine(nums, nums, nums, nums, nums, strs, strs) {
    it.reduce { a, b -> "$a $b"}
}.collect { ... }

또한 combine 은 Flow를 묶는데 개수 제한을 두지 않아 무제한으로 묶어서 사용할 수 있다.

 

인자가 5개 이하인 경우 데이터는 각각 들어오고

5개를 넘은 경우 리스트 형식으로 데이터가 들어온다.

val request = (1..3).asFlow()
val search = flowOf("Google", "Naver", "Daum")
request.combineTransform(search) { request, search ->
    emit("start request")
    delay(400)
    emit("end request $request at $search")
}.collect {
    println(it)
}

result :
start request
end request 1 at Google
start request
end request 2 at Google
start request
end request 3 at Google
start request
end request 3 at Naver
start request
end request 3 at Daum

combineTransform 를 이용하면 combinetransform 를 하나의 함수로 처리하는 것이 가능하며

combine과 동일하게 여러 개의 Flow를 대상으로 할 수 있다.

( combine 하고 transform을 따로 호출해도 결과는 동일하다. )

 

결과물이 나오는 방식은 combine 과 동일하게 최신 데이터 원하는 형태로 변환하여 방출한다.

반응형