์†Œํ”„ํ‹ฐ์–ด ๋ถ€ํŠธ์บ ํ”„ ํ•  ๋•Œ ์•ˆ๋“œ๋กœ์ด๋“œ ์Šคํ„ฐ๋””์—์„œ flow๋ฅผ ๊ณต๋ถ€ํ–ˆ๋˜๊ฒŒ ์ƒ๊ฐ๋‚ฌ๋Š”๋ฐ ๋…ธ์…˜์—๋งŒ ๋‘๊ธฐ ์•„๊นŒ์›Œ์„œ ํฌ์ŠคํŒ…ํ•œ๋‹ค.

+) ์›๋ž˜๋Š” ๋ผ์ด๋ธŒ๋ฐ์ดํ„ฐ ํ•ญ๋ชฉ์ด ๋จผ์ €์˜€๋Š”๋ฐ, ํ”Œ๋กœ์šฐ๋กœ ์ „ํ–ฅํ•˜๋Š” ์ถ”์„ธ์ธ๊ฒƒ ๊ฐ™์•„์„œ ํ”Œ๋กœ์šฐ๋ฅผ ๋งจ ์•ž์œผ๋กœ ์˜ฎ๊ฒผ๋‹ค.

๐ŸŒŠCoroutine Flow

  • ๋น„๋™๊ธฐ ์ž‘์—… ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ
  • ๋‚ด๋ณด๋‚ธ ๊ฐ’์€ ๋™์ผํ•œ ์œ ํ˜•์ด์—ฌ์•ผํ•œ๋‹ค. Flow<T>
  • suspendํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ’์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒ์‚ฐ ๋ฐ ์‚ฌ์šฉ
  • coldStream : ๊ตฌ๋…์ž ์žˆ์„๋•Œ๋งŒ ๋ฐ์ดํ„ฐ ์ƒ์„ฑํ•˜๊ณ  ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž์—๊ฒŒ ๋…๋ฆฝ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

suspend function vs flow

  • suspendํ•จ์ˆ˜๋Š” ๋‹จ์ผ ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ ๊ฐ€๋Šฅ
  • flow๋Š” ์—ฌ๋Ÿฌ๊ฐ’์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ! โ†’ ์•ฝ๊ฐ„ stream๋Š๋‚Œ!

๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ

  • ์ƒ์‚ฐ์ž(Producer) : ์ŠคํŠธ๋ฆผ์— ์ถ”๊ฐ€๋˜๋Š” ๋ฐ์ดํ„ฐ ์ƒ์‚ฐ โ†’ ์ผ๋ฐ˜์ ์œผ๋กœ ui๋ฐ์ดํ„ฐ ์ƒ์‚ฐ์ž
  • ์ค‘๊ฐœ์ž(Intermediary)(optional) : ์ŠคํŠธ๋ฆผ์ด ๋‚ด๋ณด๋‚ด๋Š” ๊ฐ’์ด๋‚˜ ์ŠคํŠธ๋ฆผ ์ž์ฒด๋ฅผ ์ˆ˜์ •๊ฐ€๋Šฅ
  • ์†Œ๋น„์ž(Consumer) : ์ŠคํŠธ๋ฆผ ๊ฐ’์„ ์‚ฌ์šฉ โ†’ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž UI

โ†’ ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ๋กœ ์‚ฌ์šฉ์ž UI๊ฐ€ ์ƒ์‚ฐ์ž๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์Œ

Flow ์‚ฌ์šฉ

์ƒ์„ฑ

  • flow{..} : FlowBuilder API์‚ฌ์šฉ, ์ฝ”๋ฃจํ‹ด ๋‚ด์—์„œ ์‹คํ–‰
  • emit() : ์ƒˆ flow ์ƒ์„ฑ
  • delay(ms) : ์ผ์‹œ์ •์ง€
val latestNews: Flow<List<ArticleHeadline>> = flow {
        while(true) {
            val latestNews = newsApi.fetchLatestNews()
            emit(latestNews) // ์ƒˆ ๋ฐ์ดํ„ฐ flow๋ฐฉ์ถœ
            delay(5000) // ์ผ์‹œ์ค‘์ง€
        }
    }

โ†’ flow๋นŒ๋”๋Š” ์ฝ”๋ฃจํ‹ด ๋‚ด์—์„œ ์‹คํ–‰๋˜์„œ ๋™์ผํ•œ ๋น„๋™๊ธฐ ์ œ์•ฝ์‚ฌํ•ญ

  1. ์ˆœ์ฐจ์ ์ธ ํ๋ฆ„
  2. ์ƒ์‚ฐ์ž๊ฐ€ ๋‹ค๋ฅธ CoroutineContext๊ฐ’์„ emit๋ถˆ๊ฐ€โ†’ ์ƒˆ๋กœ ์ฝ”๋ฃจํ‹ด ๋งŒ๋“ค๋ฉด ์•ˆ๋จ! โ†’ ์ด๊ฒฝ์šฐ callbackFlow์‚ฌ์šฉ๊ฐ€๋Šฅ

์ŠคํŠธ๋ฆผ ์ˆ˜์ •(์ค‘๊ฐ„์—ฐ์‚ฐ์ž)

  • ์ŠคํŠธ๋ฆผ ๊ฐ’์„ ์†Œ๋น„ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ์ˆ˜์ •
  • map : ๊ฐ’ ๋ณ€ํ™˜

      flowOf(1, 2, 3)
          .map { it * 2 }
          .collect { println(it) }  // ์ถœ๋ ฅ: 2, 4, 6
    
  • filter : ๊ฐ’ ํ•„ํ„ฐ๋ง

      flowOf(1, 2, 3, 4)
          .filter { it % 2 == 0 }
          .collect { println(it) }  // ์ถœ๋ ฅ: 2, 4
    
  • transform : map๋ณด๋‹ค ๋” ์œ ์—ฐํ•œ ๋ณ€ํ™˜ ์ˆ˜ํ–‰๊ฐ€๋Šฅ, ๊ฐ’ ๋ฐฉ์ถœ, ํ•„ํ„ฐ๋ง, ์˜ˆ์™ธ๋ฐœ์ƒ๊ฐ€๋Šฅ

      flowOf(1, 2, 3)
          .transform { value ->
              if (value == 2) {
                  emit(-1)
              } else {
                  emit(value)
              }
          }
          .collect { println(it) }  // ์ถœ๋ ฅ: 1, -1, 3
    

๋ฐ์ดํ„ฐ ์†Œ๋น„(ํ„ฐ๋ฏธ๋„ ์—ฐ์‚ฐ์ž)

  • collect : flow์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฐ ๋ฐ์ดํ„ฐ ์†Œ๋น„ ๋ฐ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ์•ก์…˜ ์ˆ˜ํ–‰

      flowOf(1, 2, 3)
          .collect { println(it) }  // ์ถœ๋ ฅ: 1, 2, 3
    
  • toList : ๋ฐฉ์ถœ๋˜๋Š” ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ฆฌ์ŠคํŠธ์— ์ˆ˜์ง‘

      val result: List<Int> = flowOf(1, 2, 3).toList()
      println(result)  // ์ถœ๋ ฅ: [1, 2, 3]
    
  • reduce : ๋ฐฉ์ถœ๋˜๋Š” ์š”์†Œ๋ฅผ ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ์ค„์ž„, ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฒฐํ•ฉ

      val result: Int = flowOf(1, 2, 3).reduce { acc, value -> acc + value }
      println(result)  // ์ถœ๋ ฅ: 6
    

์˜ˆ์™ธ ์ฒ˜๋ฆฌ

  • catch : ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๋ธ”๋ก ์ œ๊ณต, ์—๋Ÿฌ ๋กœ๊ทธ, ๋Œ€์ฒด๊ฐ’ ๋ฐฉ์ถœ ๊ฐ€๋Šฅ

      flow {
          emit(1)
          throw RuntimeException()
      }
      .catch { e -> println("Caught exception: $e") }
      .collect { println(it) }
    
  • onCompletion : collect์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ์„๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ธ”๋ก ์ œ๊ณต, ์„ฑ๊ณต ์—ฌ๋ถ€์™€ ์ข…๋ฃŒ ์›์ธ์„ ์•Œ ์ˆ˜ ์žˆ์Œ

      flowOf(1, 2, 3)
          .onCompletion { cause ->
              if (cause == null) {
                  println("Flow completed successfully.")
              } else {
                  println("Flow completed with exception: $cause")
              }
          }
          .collect { println(it) }
    

๋ฐฑ ํ”„๋ ˆ์…” ์ง€์›

  • ํ”Œ๋กœ์šฐ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ƒ์‚ฐํ•ด๋„ ์†Œ๋น„์ž๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
  • ์ฝ”๋ฃจํ‹ด suspendํ•จ์ˆ˜๋กœ ์ง€์›๋จ

context ์œ ์ง€

  • Flow์—ฐ์‚ฐ์ž ๋‚ด์—์„œ ์ฝ”๋ฃจํ‹ด ์ปจํƒ์ŠคํŠธ๋Š” ์ž๋™์œผ๋กœ ์ „ํŒŒ๋จ
  • Flow์—ฐ์‚ฐ์ž ์ฒด์ธ์—์„œ์˜ ๊ฐ ๋‹จ๊ณ„๋Š” ๋™์ผํ•œ ์ฝ”๋ฃจํ‹ด ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋จ์„ ๋ณด์žฅ
val myFlow = flow {
   // GlobalScope.launch { // ์‚ฌ์šฉ๋ถˆ๊ฐ€
   // launch(Dispatchers.IO) { // ์‚ฌ์šฉ๋ถˆ๊ฐ€
   // withContext(CoroutineName("myFlow")) { // ์‚ฌ์šฉ๋ถˆ๊ฐ€
   emit(1) // OK
   coroutineScope {
       emit(2) // OK -- ๊ฐ™์€ ์ฝ”๋ฃจํ‹ด์—์„œ ์‹คํ–‰๋จ
   }
}

StateFlow & SharedFlow

StateFlow

  • ์•ฝ๊ฐ„ ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ๋ž‘ ๋น„์Šท
  • ํ•ญ์ƒ ํ˜„์žฌ ์ƒํƒœ๊ฐ’ ๊ฐ€์ง€๋Š” Flow
  • ์ƒํƒœ๊ฐ’ ๋ณ€๊ฒฝ ๋ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ’์ด ์ž๋™์œผ๋กœ ๋ฐฉ์ถœ
  • ์ค‘๋ณต๋œ ๊ฐ’์€ ๋ฐฉ์ถœํ•˜์ง€ ์•Š์Œ
  • ํ•ซ์ŠคํŠธ๋ฆผ์œผ๋กœ ๊ด€์ฐฐ์ž๊ฐ€ ์—†์–ด๋„ ๊ฐ’์„ ์œ ์ง€!
val mutableStateFlow = MutableStateFlow(0)  // ์ดˆ๊ธฐ ์ƒํƒœ ๊ฐ’์œผ๋กœ 0 ์„ค์ •
val stateFlow: StateFlow<Int> = mutableStateFlow  // StateFlow ํƒ€์ž…์œผ๋กœ ๋…ธ์ถœ

// ์ƒํƒœ ๊ฐ’ ๋ณ€๊ฒฝ
mutableStateFlow.value = 5

// ์ƒํƒœ ๊ฐ’ ์‚ฌ์šฉ
println(stateFlow.value)  // ์ถœ๋ ฅ: 5

SharedFlow

  • ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ„ ์ด๋ฒคํŠธ๋‚˜ ๋ฐ์ดํ„ฐ ๊ณต์œ ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” Flow
  • ๋‹ค์ค‘์ปฌ๋ ‰ํ„ฐ ์ง€์› ( ๋ธŒ๋กœ๋“œ ์บ์ŠคํŒ… ) โ†’ ์—ฌ๋Ÿฌ UI์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ๊ตฌ๋…๊ฐ€๋Šฅ
  • ๋ฐฉ์ถœ์ •์ฑ… ์„ค์ • ๊ฐ€๋Šฅ โ†’ ๋ฒ„ํผํฌ๊ธฐ, ์ดˆ๊ณผ์‹œ ๋™์ž‘ ๋“ฑ
  • Replay๊ธฐ๋Šฅ โ†’ ์ƒˆ๋กœ์šด ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ๊ตฌ๋… ์‹œ์ž‘์‹œ ์ตœ๊ทผ ๋ฐฉ์ถœ๋œ N๊ฐœ์˜ ๊ฐ’์„ ๋‹ค์‹œ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
  • ํ•ซ ์ŠคํŠธ๋ฆผ : ๊ด€์ฐฐ์ž ์—†์–ด๋„ ํ™œ์„ฑ์ƒํƒœ ์œ ์ง€!
val sharedFlow = MutableSharedFlow<Int>()

// ๋‹ค๋ฅธ ์ฝ”๋ฃจํ‹ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฉ์ถœ
launch {
    sharedFlow.emit(1)
    sharedFlow.emit(2)
    sharedFlow.emit(3)
}

// ์—ฌ๋Ÿฌ ์ปฌ๋ ‰ํ„ฐ๊ฐ€ ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ 
launch {
    sharedFlow.collect { value ->
        println("Collector 1 received: $value")
    }
}
launch {
    sharedFlow.collect { value ->
        println("Collector 2 received: $value")
    }
}

๐Ÿณย LiveData

  • ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ํ™€๋” ํด๋ž˜์Šค

์žฅ์ 

  1. UI,๋ฐ์ดํ„ฐ์ƒํƒœ์˜ ์ผ์น˜ ๋ณด์žฅ
  2. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†์Œ โ†’ ์ˆ˜๋ช…์ฃผ๊ธฐ ๋๋‚˜๋ฉด ์ž๋™์‚ญ์ œ
  3. ์ˆ˜๋ช…์ฃผ๊ธฐ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ
  4. ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” LiveData๊ฐ์ฒด๋ฅผ ํ™•์žฅํ•ด ์‹œ์Šคํ…œ ์„œ๋น„์Šค ๋ž˜ํ•‘ ๊ฐ€๋Šฅ

์‚ฌ์šฉ

  1. LiveData์ธ์Šคํ„ด์Šค ์ƒ์„ฑ (์ผ๋ฐ˜์ ์œผ๋กœ ๋ทฐ๋ชจ๋ธ)
    • ๊ทธ๋ƒฅ ์„ ์–ธํ•˜๋ฉด ์ฒ˜์Œ์—๋Š” LiveData๊ฐ์ฒด ๋ฐ์ดํ„ฐ ์„ค์ •์•ˆ๋จ
  2. onChanged()๋ฉ”์„œ๋“œ ์ •์˜ํ•˜๋Š” Observer๊ฐ์ฒด ๋งŒ๋“ฆ
  3. observe()๋ฉ”์„œ๋“œ๋กœ LiveData์— Observer๊ฐ์ฒด ์—ฐ๊ฒฐ
    • onCreate()๊ฐ€ ์ ์ ˆ, ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” onViewCreated
    • onResume() ๋ฉ”์„œ๋“œ์—์„œ ์ค‘๋ณตํ˜ธ์ถœ ๋ฐฉ์ง€
  4. LiveData๊ฐ์ฒด ๊ฐ’ ์—…๋ฐ์ดํŠธ์‹œ ํ™œ์„ฑ์ƒํƒœ์ธ ๋ชจ๋“  ๊ด€์ฐฐ์ž๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ

๊ฐ์ฒด ์—…๋ฐ์ดํŠธ

  • ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฉ”์„œ๋“œ ์—†์Œ
  • MutableLiveDta๋Š” setValue, postValue๋ฉ”์„œ๋“œ๋ฅผ public์œผ๋กœ ๋…ธ์ถœํ•ด์„œ ์ €์žฅ๋œ ๊ฐ’ ์ˆ˜์ •
  • ๋ทฐ๋ชจ๋ธ์€ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ LiveData ๊ฐ์ฒด๋งŒ ๊ด€์ฐฐ์ž์—๊ฒŒ ๋…ธ์ถœ โ†’ backing property!

๋ทฐ๋ชจ๋ธ์—์„œ ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • ๋ทฐ๋ชจ๋ธ์€ ์ƒํƒœ๋ฅผ ๋ณด์œ 
  • UI์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ฐ์ดํ„ฐ ํ‘œ์‹œ๋ฅผ ๋‹ด๋‹นํ•˜๊ณ  ์ƒํƒœ๋Š” ๋ณด์œ ํ•˜์ง€ ์•Š์Œ
  • ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ ๋” ๊ธธ๋‹ค.

Lifecycle Aware Component

  • ์•กํ‹ฐ๋น„ํ‹ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ ๋“ฑ ์ˆ˜๋ช…์ฃผ๊ธฐ ๊ณ ๋ ค
  • ํ™œ์„ฑ ์ƒํƒœ ๊ด€์ฐฐ์ž์—๊ฒŒ๋งŒ ์—…๋ฐ์ดํŠธ ์•Œ๋ฆผ โ†’ STARTED~RESUMED
  • ๋น„ํ™œ์„ฑ ์ƒํƒœ์—์„œ ํ™œ์„ฑ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋ ๋•Œ๋„ ์—…๋ฐ์ดํŠธ ๋ฐ›์Œ โ†’ ์ด๊ฒฝ์šฐ ๊ฐ€์žฅ ์ตœ์‹  ๋ฐ์ดํ„ฐ

๊ด€์ฐฐ์ž(Observer)

  • LifecycleOwner์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด์™€ ํŽ˜์–ด๋ง๋œ ๊ด€์ฐฐ์ž
  • observerForever๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด LifecycleOwner๊ฐ์ฒด ์—†๋Š” ๊ด€์ฐฐ์ž๋ฅผ ๋“ฑ๋ก ๊ฐ€๋Šฅ

์•„ํ‚คํ…์ฒ˜๋ฅผ ์œ„ํ•œ LiveData์›์น™

  • ์•กํ‹ฐ๋น„ํ‹ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์ƒํƒœ๋ฅผ ๋ณด์œ ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ์—ญํ• ๋งŒ ํ•˜๋ฏ€๋กœ LiveData์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด์œ ํ•˜๋ฉด ์•ˆ๋จ
  • LiveData๋Š” ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์–ด์—์„œ LiveData์‚ฌ์šฉ์•ˆ๋จ.

โ†’ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ : Kotlin Flow + asLiveData๋กœ ๋ทฐ๋ชจ๋ธ์˜ LiveData๋กœ ๋ณ€ํ™˜

โ†’(์ž๋ฐ”) RxJava๋‚˜ Executor๋ฅผ ์‚ฌ์šฉ

LiveData & ROOM

  • DAO์ผ๋ถ€๋กœ ์ž‘์„ฑ
  • DB์—…๋ฐ์ดํŠธ์‹œ Room์ด LiveData์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๋Š” ์ฝ”๋“œ ์ƒ์„ฑ
  • ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋Š” ํ•„์š”์‹œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฟผ๋ฆฌ ์‹คํ–‰
  • UI ๋ฐ์ดํ„ฐ์™€ DB๋ฐ์ดํ„ฐ์˜ ๋™๊ธฐํ™”์— ์œ ์šฉ

LiveData & Coroutine

  • ์ฝ”๋ฃจํ‹ด ์ง€์› ๊ฐ€๋Šฅ

LiveData๋‚ด๋ถ€ ํ•จ์ˆ˜ (์ƒ์† ํ›„ override๊ฐ€๋Šฅ)

  • onActive() : ํ™œ์„ฑ ์ƒํƒœ์˜ ๊ด€์ฐฐ์ž๊ฐ€ ์žˆ์„๋•Œ ํ˜ธ์ถœ
  • onInactive() : ํ™œ์„ฑ์ƒํƒœ์˜ ๊ด€์ฐฐ์ž๊ฐ€ ์—†์„๋•Œ ํ˜ธ์ถœ
  • setValue(T) : LiveData์ธ์Šคํ„ด์Šค ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ  ๋ชจ๋“  ํ™œ์„ฑ ์ƒํƒœ ๊ด€์ฐฐ์ž์—๊ฒŒ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์•Œ๋ฆผ

๋ผ์ด๋ธŒ๋ฐ์ดํ„ฐ๋กœ ์•กํ‹ฐ๋น„ํ‹ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ, ์„œ๋น„์Šค ๊ฐ„ ๊ฐ์ฒด๊ณต์œ 

  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ์ ์šฉ
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager: StockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }

    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}
  • ์•ฑ ์ „์—ญ์—์„œ ํŠธ๋ฆฌ๊ฑฐ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ

LiveData ๋ณ€ํ™˜ : Transformations

  • Transforamtions.map() : ์ €์žฅ๋œ ๊ฐ’์— ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ๋ฐ˜ํ™˜
  • Transformation.switchMap() : map๊ณผ ๋น„์Šทํ•œ๋ฐ ๋ฐ˜ํ™˜๊ฐ’์ด LiveData๊ฐ์ฒด

LiveData vs StateFlow

๊ณตํ†ต์ 

  • ๊ด€์ฐฐ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ํ™€๋” ํด๋ž˜์Šค
  • ์•ฑ ์•„ํ‚คํ…์ฒ˜์—์„œ ์‚ฌ์šฉ์‹œ ๋น„์Šทํ•œ ํŒจํ„ด๋”ฐ๋ฆ„

์ฐจ์ด์ 

  • StateFlow
    • ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ƒ์„ฑ์ž์— ์ „๋‹ฌํ•ด์•ผํ•จ
    • ์ˆ˜๋ช…์ฃผ๊ธฐ์— ๋”ฐ๋ฅธ ๊ณ ๋ ค๋ฅผ ์œ„ํ•ด์„œ Lifecycle.repeatOnLifecycle์‚ฌ์šฉํ•ด์•ผํ•จ(๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›์•ˆํ•จ)
  • LiveData
    • ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ
    • ์ž๋™์œผ๋กœ ์ˆ˜๋ช…์ฃผ๊ธฐ๋ฅผ ๊ณ ๋ ค

๐Ÿ“–์ฐธ๊ณ ์ž๋ฃŒ

LiveData ๊ฐœ์š” |ย  Android ๊ฐœ๋ฐœ์ž ย |ย  Android Developers

Android Transformations

Android์˜ Kotlin Flow ย |ย  Android Developers

Flow

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ