개념
Flow는 여러 값을 순차적으로 내보낼 수 있는 비동기 스트림(콜드)이다.
데이터 스트림은 다음과 같은 세 가지 항목으로 다눌 수 있다.
생산자
Flow 스트림에 추가되는 데이터를 생산한다(emit)
중개자
Flow 스트림에 내보내는 데이터를 가공한다.(선택사항)
소비자
생산자와 중개자를 통해 생산된 데이터를 소비한다.(collect 등)
종류
생산자
flow
가장 기본적인 생산자이다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
flowOf
flow와 달리 생산 인자를 직접 입력해 줘야 한다.
fun flowNumber(): Flow<Int> = flowOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
asFlow
list와 같은 컬렉션들을 flow형태로 바꾸어 준다.
fun flowNumber(): Flow<Int> = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).asFlow()
중개자
map
흔히 사용하는 기존의 map과 같이 데이터를 재가공 할 수 있다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 1
번호 : 2
번호 : 3
번호 : 4
번호 : 5
번호 : 6
번호 : 7
번호 : 8
번호 : 9
filter
발행하는 데이터를 조건을 통해 선별 하는걸 가능하게 한다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().filter {
it % 2 == 0
}.map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 2
번호 : 4
번호 : 6
번호 : 8
filterNot
filter의 조건의 반대이다. (filter의 it%2==0은 filterNot의 it%2!=0과 같다.)
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().filterNot {
it % 2 == 0
}.map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 2
번호 : 4
번호 : 6
번호 : 8
drop
처음부터 지정한 수 만큼의 데이터를 버리고 이후 발행된 데이터를 가져온다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().drop(5).map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 5
번호 : 6
번호 : 7
번호 : 8
번호 : 9
take
처음부터 지정한 수 만큼의 데이터만 가져온다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().take(5).map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 1
번호 : 2
번호 : 3
번호 : 4
takeWhile
지정한 조건이 만족할 때 까지만 데이터를 가져온다.(앞에서 들어온 데이터가 조건에 안 맞으면 뒤에 들어오는 데이터들이 조건이 맞는다고 해도 가져오지 않는다.)
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().takeWhile {
it < 5
}.map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 1
번호 : 2
번호 : 3
번호 : 4
transform
기준 flow의 발행을 데이터를 거르거나 새로운 데이터를 발행(emit)할 수 있다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().transform {
if (it % 2 == 0) {
emit(it)
emit(it + 1)
}
}.map {
"번호 : $it"
}.collect { value ->
println(value)
}
}
}
출력)
번호 : 0
번호 : 1
번호 : 2
번호 : 3
번호 : 4
번호 : 5
번호 : 6
번호 : 7
번호 : 8
번호 : 9
소비자
collect
가장 많이 쓰이는 소비자로 생산자, 중개자를 거쳐 발행된 데이터를 발행 흐름에 따라 가져온다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
flowNumber().collect { value ->
println(value)
}
}
}
출력)
0
1
2
3
4
5
6
7
8
9
reduce
데이터를 발행할 때 이전에 발행한 데이터를 함께 가지고 와 이를 활용할 수 있다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
val sum = flowNumber()
.reduce { a, b ->
a + b
}
println(sum)
}
}
출력)
45
count
조건을 만족하는 emit된 데이터의 수를 가져온다.
fun flowNumber(): Flow<Int> = flow {
repeat(10) {
emit(it)
delay(100)
}
}
fun main() {
runBlocking {
val sum = flowNumber()
.count {
(it % 2) == 0
}
println(sum)
}
}
출력)
5
참고
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow
https://developer.android.com/kotlin/flow?hl=ko
'코틀린' 카테고리의 다른 글
inline 함수 (0) | 2022.08.31 |
---|---|
코틀린 by란? (0) | 2022.06.28 |
비동기 callback을 동기로 처리하기 suspendCoroutine, suspendCancellableCoroutine (0) | 2022.05.23 |
코틀린 StateFlow 및 SharedFlow (2) | 2022.05.21 |
코루틴 채널 개념 및 예제 (0) | 2022.05.07 |