๐Ÿ“ฑ์ฝ”ํ‹€๋ฆฐ ํ”Œ๋กœ ์ •๋ฆฌ

HBยท2025๋…„ 6์›” 3์ผ

๐Ÿ’  ์ฝ”ํ‹€๋ฆฐ ํ”Œ๋กœ

ํ”Œ๋กœ๋ž€?

  • ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ
  • ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • LiveData์ฒ˜๋Ÿผ UI์™€ ์—ฐ๋™๋„ ๊ฐ€๋Šฅํ•˜๋ฉด์„œ๋„ ๋” ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๊ณผ ์—ฐ์‚ฐ ์ œ๊ณต
  • ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฝœ๋“œ ์ŠคํŠธ๋ฆผ=> ๊ตฌ๋…ํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์•„๋ฌด ์ž‘์—…๋„ x

ViewModel์— Flow ์„ ์–ธํ•˜๊ธฐ

  • ViewModel์—์„œ Flow๋ฅผ ์„ ์–ธํ•  ๋•Œ๋Š” ๋ณดํ†ต flow {} ๋ธ”๋ก ์‚ฌ์šฉ
  • ๋ธ”๋ก ์•ˆ์—์„œ๋Š” emit() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์”ฉ ๋ฐฉ์ถœ
val numberFlow = flow {
    for (i in 1..5) {
        emit(i)
        delay(1000)
    }
}

-> ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์”ฉ, ์ผ์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ๋‚ด๋ณด๋‚ด๋Š” ๊ตฌ์กฐ ๊ฐ€๋Šฅ
-> ๋น„๋™๊ธฐ ๋ฃจํ”„์ฒ˜๋Ÿผ ์ž‘๋™

Compose์—์„œ Flow ์ˆ˜์ง‘ํ•˜๊ธฐ

  • Flow๋ฅผ ์ƒํƒœ๋กœ ๋ฐ”๊ฟ” UI์™€ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” collectAsState()๋ฅผ ์‚ฌ์šฉ
  • Flow์—์„œ ๋‚˜์˜ค๋Š” ๊ฐ’์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ›์•„ ์ƒํƒœ๋กœ ์ €์žฅํ•˜๊ณ , ์ด ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ž๋™์œผ๋กœ UI๋ฅผ ๋‹ค์‹œ ๊ทธ๋ ค์คŒ

=> ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ UI์™€ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ

val number by viewModel.numberFlow.collectAsState(initial = 0)

Flow ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ž ์‚ฌ์šฉํ•˜๊ธฐ

  • Flow๋Š” ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ ํ๋ฆ„๋งŒ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๊ณตํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ๋‹ค์–‘ํ•œ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ž ์ œ๊ณต
    ex) map์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ณ , filter๋Š” ์กฐ๊ฑด์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋งŒ ํ†ต๊ณผ
val newFlow = numberFlow
    .filter { it % 2 == 0 }
    .map { it * 10 }

=> Flow๋Š” ์ฒด์ด๋‹ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
=> ๋ณต์žกํ•œ ๋กœ์ง๋„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ ๊ฐ€๋Šฅ

๋ฒ„ํผ ์‚ฌ์šฉํ•˜๊ธฐ

  • buffer()๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์‚ฐ์ž๊ฐ€ ๋น ๋ฅด๋”๋ผ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์ž ์‹œ ์ €์žฅํ•ด๋‘๊ณ , ์†Œ๋น„์ž๊ฐ€ ๋”ฐ๋ผ์žก์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•จ
numberFlow
    .buffer()
    .collect { ... }

=> ์‹ค์ œ ์•ฑ์—์„œ ๋„คํŠธ์›Œํฌ ์†๋„, ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์†๋„ ์ฐจ์ด ๋“ฑ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉ

์ข…๋‹จ ์—ฐ์‚ฐ์ž

  • Flow๋Š” ๋งˆ์ง€๋ง‰์— ๋ฐ˜๋“œ์‹œ ์ข…๋‹จ ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ์–ด์•ผ ์‹คํ–‰
  • ๋Œ€ํ‘œ์ ์ธ ๊ฒƒ: collect()

=> flow๋กœ ์ •์˜๋งŒ ํ•ด๋†“๊ณ  collect()๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด ์ผ๋„x

numberFlow.collect { value ->
    Log.d("TAG", "๊ฐ’: $value")
}
  • first(), toList() ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ข…๋‹จ ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์šฉ

Flow ํ‰ํƒ„ํ™”

  • ์ด์ค‘ ๊ตฌ์กฐ๋ฅผ ํ‰ํƒ„ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ : flatMap ๊ณ„์—ด ํ•จ์ˆ˜

  • flatMapConcat: ์ˆœ์ฐจ์ ์œผ๋กœ ์—ฐ๊ฒฐ

  • flatMapMerge: ๋ณ‘๋ ฌ๋กœ ์—ฐ๊ฒฐ

  • flatMapLatest: ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๊ฒƒ๋งŒ ์œ ์ง€

ex) ๊ฒ€์ƒ‰์–ด ์ž๋™์™„์„ฑ ๊ฐ™์€ ๊ธฐ๋Šฅ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ์„ ๋ฐ”๊ฟ€ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด API ํ˜ธ์ถœ์ด ํ•„์š”=> flatMapLatest๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉ

ํ•ซ ํ”Œ๋กœ์™€ ์ฝœ๋“œ ํ”Œ๋กœ์˜ ์ฐจ์ด

  • Flow๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฝœ๋“œ
    => ๊ตฌ๋…์ž๊ฐ€ collectํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กญ๊ฒŒ ์‹คํ–‰
  • StateFlow์™€ SharedFlow๋Š” ํ•ซ ํ”Œ๋กœ
    => ํ•œ ๋ฒˆ ๋ฐฉ์ถœ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์†ํ•ด์„œ ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž์—๊ฒŒ ์ „๋‹ฌ ๊ฐ€๋Šฅ
  • ํ•ซ ํ”Œ๋กœ๋Š” ์ด๋ฏธ ์‹คํ–‰ ์ค‘์ธ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ
    ex) ๋กœ๊ทธ์ธ ์ƒํƒœ, ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ

์ฝœ๋“œ Flow๋ฅผ ํ•ซ Flow๋กœ ์ „ํ™˜ํ•˜๊ธฐ

  • shareIn() ๋˜๋Š” stateIn() ๊ฐ™์€ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด์˜ ์ฝœ๋“œ Flow๋ฅผ ํ•ซ Flow๋กœ ์ „ํ™˜ ๊ฐ€๋Šฅ
    => Flow๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž๊ฐ€ ๊ฐ’์„ ๊ณต์œ  ๊ฐ€๋Šฅ
val hotFlow = coldFlow.shareIn(scope, SharingStarted.Eagerly)



๐Ÿ’  SharedFlow

SharedFlow๋ž€?

  • ์ผํšŒ์„ฑ ์ด๋ฒคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž์—๊ฒŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ํ•ซ ํ”Œ๋กœ
  • ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€, ๋„ค๋น„๊ฒŒ์ด์…˜ ์ด๋™, ๋‹ค์ด์–ผ๋กœ๊ทธ ํ‘œ์‹œ์ฒ˜๋Ÿผ UI ์ด๋ฒคํŠธ์— ์ ํ•ฉ
  • StateFlow์™€๋Š” ๋‹ฌ๋ฆฌ ๊ฐ’์„ ๊ธฐ์–ตํ•˜์ง€ ์•Š๊ณ , emit() ํ•˜๋ฉด ๊ตฌ๋… ์ค‘์ธ ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์Œ

SharedFlowDemo ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ

  1. ViewModel์— MutableSharedFlow๋ฅผ ์„ ์–ธ

  2. ๋ฒ„ํŠผ ํด๋ฆญ ๋“ฑ์œผ๋กœ emit() ์‹คํ–‰

  3. Composable์—์„œ๋Š” LaunchedEffect๋กœ ์ˆ˜์ง‘

=> ์ด๋ฒคํŠธ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ UI์™€ ์—ฐ๊ฒฐํ•  ๋•Œ ์ง๊ด€์ 

Compose์—์„œ SharedFlow ์ˆ˜์ง‘

  • Compose์—์„œ SharedFlow๋ฅผ ์ˆ˜์ง‘ํ•  ๋• LaunchedEffect(Unit) ๋ธ”๋ก ์‚ฌ์šฉ
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋‚˜ํƒ€๋‚  ๋•Œ ํ•œ ๋ฒˆ ์‹คํ–‰๋˜๊ณ , ๋‚ด๋ถ€์—์„œ collect()๋ฅผ ํ†ตํ•ด ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€
  • ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ โ†’ Toast ํ‘œ์‹œ ๊ฐ™์€ ๋กœ์ง์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ตฌํ˜„

  • Flow๋Š” ์ˆœ์ฐจ์  ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์œ„ํ•œ ์ฝ”๋ฃจํ‹ด ๊ธฐ๋ฐ˜ ๋„๊ตฌ
  • collectAsState๋กœ Compose์™€ ์—ฐ๋™ ๊ฐ€๋Šฅ
  • map, filter, buffer, combine, flatMapLatest ๋“ฑ ๋‹ค์–‘ํ•œ ์—ฐ์‚ฐ์ž ์ œ๊ณต
  • SharedFlow๋Š” ์ผํšŒ์„ฑ UI ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ์— ์ตœ์ 
  • Compose์—์„œ๋Š” LaunchedEffect๋กœ SharedFlow ์ˆ˜์ง‘

0๊ฐœ์˜ ๋Œ“๊ธ€