본문 바로가기

코틀린

코틀린 플로우

반응형

개념

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 

 

반응형