Kotlin flow

2023. 7. 25. 11:29개발/Kotlin

Flow?

  • 비동기 및 스트림기반 데이터 처리를 위한 반응형 프로그래밍 모델을 제공.
  • 네트워크 요청 / db쿼리 또는 ui이벤트와 같은 비동기 작업 처리

Kotlin flow basic

  • Producer : 값을 비동기적으로 생성하는 함수 / 코루틴. emit()으로 방출
  • Consumer : 흐름에서 방출된 값을 소비하는 함수 / 코루틴.
  • Operator : flow에서 다른 작업을 변환, 필터링, 결합
  • Collector : flow에서 내보낸 값을 받아 처리하는 함수

Kotlin flow의 유형

Cold Flow : flow builder사용. 값을 collect하시 전까지 생성x

  • Flow<>
val simpleFlow = flow {
 for (i in 1..3) {
 delay(1000) // pretend we're doing some work
 emit(i) // emit next value
 }
}

Hot Flow : 항상 값이 존재. 최신 값만 보내고, 초기값 필요

  • StateFlow
val simpleFlow = flow {
 for (i in 1..3) {
 delay(1000) // pretend we're doing some work
 emit(i) // emit next value
 }
}
  • SharedFlow
val stateFlow = MutableStateFlow("Hello")

viewModelScope.launch {
    repeat(10) { i ->
        delay(1000)
        stateFlow.value = "Hello $i"
    }
}

lifecycleScope.launchWhenStarted {
    stateFlow.collect {
        Log.d("StateFlow", it)
    }
}

Flow collector

  • suspend func; 최신 값을 collect함
override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
lifecycleScope.launch {
 simpleFlow.collect { value ->
 // update UI
 }
 }
}

Flow Builder

  • Flow{} 사용하면 비동기적 방출 흐름을 제어 할 수 있음.
  • suspend / coroutine과 사용 가능
val flow = flow {
    for (i in 1..5) {
        delay(1000) // Simulate asynchronous delay
        emit(i)
    }
}
  • flowOf()를 사용하면 고정된 값 집합에서 flow 만들 수 있음
val simpleFlow = flowOf("string1", "string2", "string3")
  • asFlow() 는 다양한 유형의 컬렉션, 시퀀스 등을 flow로 변환
val list = listOf(1, 2, 3, 4, 5)
val flow = list.asFlow()

Flow Operator

Intermediate Operators

  • filter
flowOf(1, 2, 3, 4, 5)
    .filter { it % 2 == 0 }
    .collect { println(it) }  // Prints 2, 4
  • map
flowOf(1, 2, 3, 4, 5)
    .map { it * it }
    .collect { println(it) }  // Prints 1, 4, 9, 16, 25
  • runningReduce
flowOf(1, 2, 3, 4, 5)
    .runningReduce { accumulator, value -> accumulator + value }
    .collect { println(it) }  // Prints 1, 3, 6, 10, 15
  • onEach
flowOf(1, 2, 3, 4, 5)
    .onEach { println("Emitting $it") }  // Perform an action on each emission
    .collect()
  • transform
flowOf(1, 2, 3, 4, 5)
    .transform { value -> emit(value * value) }
    .collect { println(it) }  // Prints 1, 4, 9, 16, 25

Size-limiting Operator

  • drop
flowOf(1, 2, 3, 4, 5)
    .drop(2)
    .collect { println(it) }  // Prints 3, 4, 5
  • dropWhile
flowOf(1, 2, 3, 4, 5)
    .dropWhile { it < 3 }
    .collect { println(it) }  // Prints 3, 4, 5
  • take
flowOf(1, 2, 3, 4, 5)
    .take(2)
    .collect { println(it) }  // Prints 1, 2
  • takeWhile
flowOf(1, 2, 3, 4, 5)
    .takeWhile { it < 3 }
    .collect { println(it) }  // Prints 1, 2

Terminal Operators

  • collect
flowOf(1, 2, 3, 4, 5)
    .collect { println(it) }  // Prints 1, 2, 3, 4, 5
  • toList
val list = flowOf(1, 2, 3, 4, 5)
    .toList()  // list: List<Int> = [1, 2, 3, 4, 5]
  • toSet
val set = flowOf(1, 2, 2, 3, 3, 3)
    .toSet()  // set: Set<Int> = [1, 2, 3]
  • count
val numbers = flowOf(1, 2, 3, 4, 5)
val count = numbers.count()
// count = 5

val evenNumbersCount = numbers.count { it % 2 == 0 }
// evenNumbersCount = 2
  • first
val numbers = flowOf(1, 2, 3, 4, 5)
val first = numbers.first()
// first = 1

val firstEvenNumber = numbers.first { it % 2 == 0 }
// firstEvenNumber = 2
  • last
val numbers = flowOf(1, 2, 3, 4, 5)
val last = numbers.last()
// last = 5

val lastEvenNumber = numbers.last { it % 2 == 0 }
// lastEvenNumber = 4
  • reduce
val numbers = flowOf(1, 2, 3, 4, 5)
val sum = numbers.reduce { acc, value -> acc + value }
// sum = 15
  • fold
val numbersFlow = flowOf(1, 2, 3, 4, 5)
val sum = numbersFlow.fold(0) { accumulator, number ->
    accumulator + number
}
println(sum) // Prints: 15

Flattening Operators

val stringsFlow = flowOf("1", "2", "3")
val numbersFlow = stringsFlow.flatMapConcat { string ->
    flow {
        emit(string.toInt())
    }
}
numbersFlow.collect { number ->
    println(number) // Prints: 1, then 2, then 3
}

Buffering Flows

  • .collect{…} 블록을 별도의 코루틴으로 시작할 수 있음
simpleFlow
 .buffer()
 .collect { value ->
 println(value)
 }

Flow error catch

flow.catch { exception ->
    // Handle the exception
    println("An error occurred: $exception")
}.collect { value ->
    // Process the value
    println(value)
}

Flow Context 지정

flow.flowOn(Dispatchers.IO).collect { value ->
    // Perform operations in IO context
    println(value)
}

Flow의 제약사항

  • Single collector : 여러 플로우는 지원되지 않음
  • Cold Stream : collect 될때만 값을 emit
  • Cancellation : flow가 취소되면, producer도 취소가 가능하다.


Uploaded by N2T

'개발 > Kotlin' 카테고리의 다른 글

RxKotlin  (0) 2023.07.26
Kotlin operator extension  (0) 2023.07.25
reified + inline  (0) 2023.05.03
Kotlin Infix func  (0) 2023.05.03
Retrofit to Ktor  (0) 2023.05.03