๐Ÿ˜ฑ 2025 ์•ˆ๋“œ๋กœ์ด๋“œ ํƒ๊ตฌ์˜์—ญ, Coroutines Flow ๋•Œ๋ฌธ์—?! (feat. ์‰ฌ์šด ํ•ด์„ค)

๐Ÿ˜ฑ 2025 ์•ˆ๋“œ๋กœ์ด๋“œ ํƒ๊ตฌ์˜์—ญ, Coroutines Flow ๋•Œ๋ฌธ์—?! (feat. ์‰ฌ์šด ํ•ด์„ค)



๊ฐœ์ธ ๊ด‘๊ณ  ์˜์—ญ

์ด ๊ธ€์€ 2025 ์•ˆ๋“œ๋กœ์ด๋“œ ํƒ๊ตฌ ์˜์—ญ์— ๋‚˜์˜จ ๋ฌธ์ œ ์ค‘ flow์™€ ๊ด€๋ จํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด์„ํ•œ ๊ธ€์ด๋‹ค.

์•ˆ๋“œ๋กœ์ด๋“œ ํƒ๊ตฌ ์˜์—ญ ํ›„๊ธฐ ๊ธ€

๋ฌด์Šจ ๋ฌธ์ œ์ธ๊ฐ€?

์ฝ”๋ฃจํ‹ด flow์— ๋Œ€ํ•œ ๋ฌธ์ œ๊ฐ€ ํฌ๊ฒŒ 2๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ์ด ์ค‘ ์ฝ”๋ฃจํ‹ด ์˜์—ญ์— ํฌํ•จํ•œ 1๊ฐœ์˜ ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ ค ํ•œ๋‹ค.

์ด ๋ฌธ์ œ๋Š” StateFlow์™€ flow {}๋ฅผ ๋ณตํ•ฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

์ด ๋ฌธ์ œ์— ๋‚˜์˜ค๋Š” Flow์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์ด์ „์— ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ์— ์ž‘์„ฑํ–ˆ๋˜ ๋‹ค์–‘ํ•œ ๊ธ€์ด ์žˆ์œผ๋‹ˆ ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ด ๊ธ€์—์„œ๋Š”

  • 2025 ์•ˆ๋“œ๋กœ์ด๋“œ ํƒ๊ตฌ ์˜์—ญ์— ๋‚˜์˜จ ๋ฌธ์ œ ์ผ๋ถ€๋ฅผ ์ •๋ฆฌํ•œ๋‹ค.
  • Coroutiens flow์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž

์•„๋ž˜๊ฐ€ ๋ฌธ์ œ์—์„œ ๋‚˜์˜จ ์ „์ฒด ์ฝ”๋“œ์ด๋‹ค.(Test ๋ถ€๋ถ„์€ ์ˆ˜์ •)

@Test
fun test() = runTest {
    val stateFlow = MutableStateFlow(1)

    val flow = flow {
        emit(1)
        delay(1_000L)
        emit(2)
        delay(1_000L)
        emit(3)
    }
        .flatMapLatest { value ->
            stateFlow
                .map {
                    value + it
                }
        }

    launch {
        delay(999L)
        stateFlow.emit(2)
        delay(999L)
        stateFlow.emit(3)
    }

    flow
        .collect { value -> println("value: $value") }
}

์ด ๋ฌธ์ œ์—์„œ๋Š” 1 ๊ฐœ์˜ StateFlow์™€ 1 ๊ฐœ์˜ flow {}๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , flow ๋‹ค์Œ์— flatMapLatest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ StateFlow๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ํ๋ฆ„์„ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ์ด๋‹ค.


flatMapLatest๋Š” ๋ฌด์—‡์ธ๊ฐ€?

flatMapLatest - link์˜ ํ•จ์ˆ˜ ์›ํ˜•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

@ExperimentalCoroutinesApi
public inline fun <T, R> Flow<T>.flatMapLatest(@BuilderInference crossinline transform: suspend (value: T) -> Flow<R>): Flow<R> =
    transformLatest { emitAll(transform(it)) }

๋ฌธ์„œ์˜ ์„ค๋ช… ๊ทธ๋Œ€๋กœ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด


Returns a flow that switches to a new flow produced by transform function every time the original flow emits a value. When the original flow emits a new value, the previous flow produced by transform block is cancelled.


์ œ๋ฏธ๋‚˜์ด์—๊ฒŒ ํ•ด์„์„ ์š”์ฒญํ•œ ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.


์ด ์ฝ”๋“œ๋Š” ์›๋ณธ flow๊ฐ€ ๊ฐ’์„ ๋‚ด๋ณด๋‚ผ ๋•Œ๋งˆ๋‹ค transform ํ•จ์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋œ ์ƒˆ๋กœ์šด flow๋กœ ์ „ํ™˜ํ•˜๋Š” flow๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ข€ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉด,

  • flow๋Š” ์ฝ”๋ฃจํ‹ด์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋งˆ์น˜ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๊ฐ’์„ ๋‚ด๋ณด๋‚ด๋Š” ์ŠคํŠธ๋ฆผ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • transform์€ flow์˜ ๊ฐ ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ƒˆ๋กœ์šด flow๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. flatMapLatest๋Š” flow์˜ ๊ฐ ๊ฐ’์— ๋Œ€ํ•ด transform ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ƒˆ๋กœ์šด flow๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด flow๋“ค์˜ ๊ฐ’์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ด๋Š” ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.
  • ์ค‘์š”ํ•œ ์ ์€, ์›๋ณธ flow๊ฐ€ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋‚ด๋ณด๋‚ผ ๋•Œ๋งˆ๋‹ค ์ด์ „์— transform ํ•จ์ˆ˜์— ์˜ํ•ด ์ƒ์„ฑ๋œ flow๋Š” ์ทจ์†Œ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํ•ญ์ƒ ์ตœ์‹  ๊ฐ’์— ๋Œ€ํ•œ flow๋งŒ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” flow๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. flatMapLatest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ์ด์ „ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ flow๋Š” ์ทจ์†Œ๋˜๊ณ  ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์–ด์— ๋Œ€ํ•œ flow๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ์ตœ์‹  ๊ฐ’๋งŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋งŒ ํ‘œ์‹œํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ flatMapLatest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์„ ๋ฐฉ์ง€ํ•˜๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์—ฌ๊ธฐ์„œ ๋งˆ์ง€๋ง‰์˜ cancel ๋ถ€๋ถ„์ด ๊ถ๊ธˆํ•˜์—ฌ ์ƒ์„ธ ์ฝ”๋“œ๋ฅผ ์ข€ ๋” ์‚ดํŽด๋ณด์•˜๋Š”๋ฐ, collect {} ์ฒ˜๋ฆฌ ํ›„ apply ๋ถ€๋ถ„์—์„œ cancel()๊ณผ join()์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ, ํ•ญ์ƒ ์ตœ์‹ ์˜ ๊ฐ’๋งŒ์„ ํ˜๋ ค๋ณด๋ƒ„์„ ์ฝ”๋“œ๋กœ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

internal class ChannelFlowTransformLatest<T, R>(
    private val transform: suspend FlowCollector<R>.(value: T) -> Unit,
    flow: Flow<T>,
    context: CoroutineContext = EmptyCoroutineContext,
    capacity: Int = Channel.BUFFERED,
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
) : ChannelFlowOperator<T, R>(flow, context, capacity, onBufferOverflow) {
    override fun create(context: CoroutineContext, capacity: Int, onBufferOverflow: BufferOverflow): ChannelFlow<R> =
        ChannelFlowTransformLatest(transform, flow, context, capacity, onBufferOverflow)

    override suspend fun flowCollect(collector: FlowCollector<R>) {
        assert { collector is SendingCollector } // So cancellation behaviour is not leaking into the downstream
        coroutineScope {
            var previousFlow: Job? = null
            flow.collect { value ->
                previousFlow?.apply { // ์ด ๋ถ€๋ถ„
                    cancel(ChildCancelledException())
                    join()
                }
                // Do not pay for dispatch here, it's never necessary
                previousFlow = launch(start = CoroutineStart.UNDISPATCHED) {
                    collector.transform(value)
                }
            }
        }
    }
}

๊ฒฐ๊ตญ flatMapLatest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด 2 ๊ฐœ์˜ flow ํ๋ฆ„์„ ํ•ฉ์น  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด์ „ ํ๋ฆ„์˜ ๋ฐ์ดํ„ฐ๋Š” ์–ธ์ œ๋‚˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์‚ฌ์šฉํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.


๋Œ์•„๊ฐ€์„œ

MutableStateFlow๋Š” ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ์ตœ์‹  ๋ฐ์ดํ„ฐ 1 ๊ฐœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„์ด๋ฉฐ, HotFlow์ด๋‹ค. ์–ธ์ œ๋‚˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋งŒ์„ ๊ฐ€์ง„๋‹ค.

๋ฐ˜๋Œ€๋กœ flow๋Š” ๊ตฌ๋…ํ•˜๊ธฐ ์ „์—๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ColdFlow์— ์†ํ•œ๋‹ค.

val stateFlow = MutableStateFlow(1)

val flow = flow {
    emit(1)
    delay(1_000L)
    emit(2)
    delay(1_000L)
    emit(3)
}
    .flatMapLatest { value ->
        stateFlow
            .map {
                value + it
            }
    }

๊ทธ๋Ÿผ ์ด ์ฝ”๋“œ์—์„œ์˜ ๊ตฌ๋… ์‹œ์ ์€ ์ด์–ด์„œ ๋‚˜์˜ค๋Š” ์ฝ”๋“œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ, launch {}๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜์„œ ๋ฐ”๋กœ collect๋ฅผ ํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

launch {
    delay(999L)
    stateFlow.emit(2)
    delay(999L)
    stateFlow.emit(3)
}

flow
    .collect { value -> println("value: $value") }


๊ตฌ๋…ํ•œ ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ

์ด ๋ฌธ์ œ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ , ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•ด์•ผ ํ•ด์„œ delay๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ œ๊ณตํ•ด ์ฃผ๊ณ  ์žˆ๋‹ค.

๊ตฌ๋…์ด ์‹œ์ž‘๋˜๋ฉด emit(1)์„ ์‹œ์ž‘ํ•˜๊ณ , 1์ดˆ์˜ ๋Œ€๊ธฐ๊ฐ€ ๊ฑธ๋ฆฐ๋‹ค. ๊ทธ๋Ÿผ StateFlow์˜ 1๊ณผ emit 1์„ ํ•ฉ์‚ฐํ•˜์—ฌ 2 ์ถœ๋ ฅ, ์ด์–ด์„œ 999ms ํ›„์— stateFlow์— 2๋ฅผ ์ „๋‹ฌํ•˜์˜€์œผ๋ฏ€๋กœ 1+2์˜ ๊ฒฐ๊ณผ 3์„ ์ถœ๋ ฅํ•œ๋‹ค.

์ดํ›„์˜ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ฉํ•˜๋ฉด 2, 3, 4, 5, 6์ด ์ˆœ์ฐจ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.


์ด ๋ฌธ์ œ์˜ ๋‹ต์€

์‚ฌ์‹ค ์œ„ ์ฝ”๋“œ๋ฅผ ํ•ด์„ํ•  ํ•„์š”๋„ ์—†๋Š” ๊ฐ„๋‹จํ•œ ๋ฌธ์ œ์ด๋‹ค.

StateFlow์— emit(2)๋ฅผ ํ•˜๋ฉด flow {} emit(1)๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ฐœํ–‰๋˜์–ด์ง„๋‹ค. ๋ผ๋Š” ๋ถ€๋ถ„์ด๋‹ค.

flatMapLatest์— ๊ฑธ์–ด๋‘” StateFlow์— ๊ฐ’์„ ๋„˜๊ธฐ๋”๋ผ๋„ flow {} ๋ถ€ํ„ฐ ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฑด ์ผ์–ด๋‚  ์ˆ˜ ์—†๋‹ค. ํ•˜์ง€๋งŒ exception์ด ๋ฐœ์ƒํ•˜๊ณ , retry๋ฅผ ๊ฑธ์—ˆ๋‹ค๋ฉด flow {}๋ถ€ํ„ฐ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

retry ์œ„์น˜๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•œ๋ฐ, ์ด์ „์— ์ž‘์„ฑํ•œ ๊ธ€์˜ ์ตœํ•˜๋‹จ ์‹œ๋‚˜๋ฆฌ์˜ค 2 ๋ฒˆ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด๊ธธ


StateFlow๊ฐ€ ์•„๋‹ˆ๋ผ SharedFlow๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด?

๋ฌธ์ œ๋ฅผ ์กฐ๊ธˆ ๋ฐ”๊ฟ” StateFlow ๋Œ€์‹  SharedFlow๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ฝ”๋“œ์˜ ๋™์ž‘์€ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

@Test
fun test() = runTest {
    val sharedFlow = MutableSharedFlow<Int>()

    val flow = flow {
        emit(1)
        delay(1_000L)
        emit(2)
        delay(1_000L)
        emit(3)
    }
        .flatMapLatest { value ->
            sharedFlow
                .map {
                    value + it
                }
        }

    launch {
        delay(999L)
        sharedFlow.emit(2)
        delay(999L)
        sharedFlow.emit(3)
    }

    flow
        .collect { value -> println("value: $value") }
}

์ด ์ฝ”๋“œ์˜ ์‘๋‹ต์€ ํ™•์—ฐํ•˜๊ฒŒ ๋‹ฌ๋ผ์ง€๋Š”๋ฐ 3, 5 ๋งŒ์ด ์ถœ๋ ฅ๋œ๋‹ค.

SharedFlow๋Š” replay๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด ์˜ค๊ธฐ ์ „์—๋Š” ๋ฐ˜์‘ ์ž์ฒด๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ž˜์„œ ์ด ์ฝ”๋“œ๋Š”

emit(1)์„ ํ•˜๋”๋ผ๋„ printlnํ•˜์ง€ ์•Š๊ณ  sharedFlow์— 2๊ฐ€ ๋“ค์–ด์™€์•ผ ๋งŒ 1+2ํ•˜์—ฌ 3์ด ์ถœ๋ ฅ๋œ๋‹ค.


StateFlow, SharedFlow, flow๋ฅผ ์…‹ ๋‹ค ํ•ฉ์„ฑํ•œ๋‹ค๋ฉด?

merge, combine, zip์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ MutableStateFlow๋ฅผ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜๊ณ  flatMapLatest๋ฅผ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜์—ฌ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”๊ฐ€ํ•ด ๋ณด์•˜๋‹ค.

@Test
fun test() = runTest {
    val sharedFlow = MutableSharedFlow<Int>()
    val stateFlow = MutableStateFlow(false)

    val flow = flow {
        emit(1)
        delay(1_000L)
        emit(2)
        delay(1_000L)
        emit(3)
    }
        .flatMapLatest { value ->
            sharedFlow
                .map {
                    value + it
                }
        }
        .flatMapLatest { // ์—ฌ๊ธฐ์— ์ถ”๊ฐ€
            stateFlow
                .filter { it }
        }

    launch {
        delay(999L)
        sharedFlow.emit(2)
        delay(999L)
        sharedFlow.emit(3)
        stateFlow.value = true // ์—ฌ๊ธฐ์— ์ถ”๊ฐ€
    }

    flow
        .collect { value -> println("value: $value") }
}

์ด ์ฝ”๋“œ๋Š” ์•ž์— ์ฝ”๋“œ๋ณด๋‹ค ๋” ์‰ฝ๊ฒŒ ๋”ฑ ํ•œ ๋ฒˆ์˜ ๊ฐ’๋งŒ์ด ์ถœ๋ ฅ๋˜๋Š”๋ฐ, ์ด ๊ฐ’์€ true์ด๋‹ค.

์™œ true์ธ์ง€๋Š” flatMapLatest๋ฅผ ์ดํ•ดํ•œ๋‹ค๋ฉด ๋งค์šฐ ์‰ฝ๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๋‹ค.


๋งˆ๋ฌด๋ฆฌ

์ด์ „์— ์ž‘์„ฑํ•œ ๊ธ€ ๋ณด๋‹ค flow๊ฐ€ ๋” ์‰ฝ๊ฒŒ ๋Š๊ปด์งˆ ์ˆ˜ ์žˆ๋‹ค. Job()์„ ์ดํ•ดํ•˜๋Š” ๋ถ€๋ถ„์ด ๋” ๋ช…ํ™•ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๊ธฐ๋„ ํ•˜๊ณ , flow๋Š” 1๊ฐœ๋กœ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ launch {}๋Š” launch ์•ˆ์— launch๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋Š” ์ง€ํ–ฅํ•˜๋Š” ํŽธ์ด ๋ชจ๋‘๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด๋ฐ ์ด๋ ‡๊ฒŒ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์‚ฌ์‹ค ๋งŽ์ง„ ์•Š๊ธด ํ•˜๋‹ค.

launch {
    launch {
        launch {
            // ...
        }
    }
}

flow๋Š” ํ•˜๋‚˜์˜ ํ๋ฆ„๋งŒ์„ ์ดํ•ดํ•˜๋ฉด ๋˜๋Š”๋ฐ ๊ทธ ์‚ฌ์ด์— ๊ฐ’์˜ ํ๋ฆ„์ด A to B๋กœ ๋ฐ”๋€Œ๋Š” ํ๋ฆ„๋งŒ ์ดํ•ดํ•˜๋ฉด ํ•ด์„์ด ์‰ฌ์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.



About Taehwan

My name is Taehwan Kwon. I have developed Android for 6 years and blog has been active for eight years.

Comments