๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ‘ฉ‍๐Ÿ’ป TECH

[TECH] Kotlin Coroutine์„ ์จ์•ผํ•˜๋Š” ์ด์œ 

by ๋ณด๋ฆฌ ์ฝง๊ตฌ๋ฉ 2023. 9. 22.

[ํ‹ฐ๋Œ] ํ‹ฐ๋Œ Android Kotlin Coroutine์„ ์จ์•ผ ํ•˜๋Š” ์ด์œ ์™€ ์‚ฌ์šฉ๋ฒ•
 
์•ˆ๋…•ํ•˜์„ธ์š” ํ‹ฐํ”Œ์˜ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž ์ •์ฑ„ํ˜„์ž…๋‹ˆ๋‹ค๐Ÿ˜†๐Ÿ˜†๐Ÿ˜†๐Ÿ˜†

์ด๋ฒˆ์—๋Š” ๋ฉ€๊ฒŒ๋งŒ ๋А๊ปด์ง€๊ณ  ์ฒ˜์Œ ๋ณด๋ฉด ์–ด๋ ต๊ฒŒ ๋А๊ปด์ง€๋Š” ๊ฐœ๋…์„ ์ €๋„ ์ •๋ฆฌํ•˜๋ฉด์„œ ํ™•์ธํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

์•ˆ๋“œ๋กœ์ด๋“œ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ์‚ฌ๋žŒ์ด๋ผ๋ฉด Coroutine์„ ๋“ค์–ด๋ณด์…จ์„ ๊ฑฐ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Coroutine์€ ๋ฌด์—‡์ด๊ณ  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๋Ÿฌ ๊ฐ€๋ด…์‹œ๋‹ค.๐Ÿ’จ


๐Ÿ‘ฉ‍๐Ÿ’ป Coroutine? ์ฝ”๋ฃจํ‹ด์ด ๋ญ์•ผ?

์ฝ”๋ฃจํ‹ด์„ ์••์ถ•ํ•ด์„œ ์„ค๋ช…ํ•˜์ž๋ฉด ์‰ฌ์šด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋กœ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ณ  ๊ฐ€๋…์„ฑ ๋†’๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์„ ๊ฐ€์ง„ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด(Coroutines)์€ Kotlin์—์„œ ๋™์‹œ์„ฑ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด์€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•˜์—ฌ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๊ณ , ๋ณต์žกํ•œ ์ฝœ๋ฐฑ์ด๋‚˜ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ํŒจํ„ด์— ๋น„ํ•ด ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

 

์ฝ”๋ฃจํ‹ด์€ ์œ„ํ‚คํ”ผ๋””์•„์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์‹คํ–‰์˜ ์ง€์—ฐ๊ณผ ์žฌ๊ฐœ๋ฅผ ํ—ˆ์šฉํ•จ์œผ๋กœ์จ, ๋น„์„ ์ ์  ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น์„ ์œ„ํ•œ 
์„œ๋ธŒ ๋ฃจํ‹ด์„ ์ผ๋ฐ˜ํ™”ํ•œ ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ ๊ตฌ์„ฑ์š”์†Œ


*๋น„์„ ์ ์  ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น

  • ์„ ์ ํ˜• : task๊ฐ€ cpu๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋”๋ผ๋„ ์ด๊ฑธ ๋บ์–ด์„œ ์ค‘๋‹จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋น„์„ ์ ํ˜• : task๊ฐ€ cpu ์‚ฌ์šฉ๊ถŒ์„ ํ• ๋‹น๋ฐ›์•˜์„ ๋•Œ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๊ฐ•์ œ๋กœ cpu์‚ฌ์šฉ๊ถŒ์„ ๋บ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. 

์ฝ”๋ฃจํ‹ด์€ ๋ณ‘ํ–‰์„ฑ์€ ์ œ๊ณตํ•˜์ง€๋งŒ, ๋ณ‘๋ ฌ์„ฑ์€ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ๋ณ‘ํ–‰์„ฑ(Concurrency) : ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ณ‘๋ ฌ๋กœ ์ž‘์—…์ด ์‹คํ–‰๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ๋ณด์ด๋Š” ๊ฒƒ (๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ณ‘๋ ฌ๋กœ ์ž‘์—…์ด ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š”  ์ฒ˜๋ฆฌ = ๋™์‹œ์„ฑ)
  • ๋ณ‘๋ ฌ์„ฑ(Parallelism) : ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ณ‘๋ ฌ๋กœ ์ž‘์—…์ด ์‹คํ–‰๋˜๋Š” ๊ฒƒ (์‹ค์ œ๋กœ ๋™์‹œ์— ์ž‘์—…์ด ์ฒ˜๋ฆฌ)

 


๐Ÿ‘ฉ‍๐Ÿ’ป ์ฝ”๋ฃจํ‹ด์„ ์™œ ์จ์•ผ ํ•˜๋Š”๋ฐ?

์ฝ”๋ฃจํ‹ด

Task1, Task2, Task3 ์ด ์™„๋ฃŒ๋˜์–ด์•ผ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ’์„ ๋ณด๋ ค๋ฉด ์ด 28์ดˆ๊ฐ€ ๊ฑธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.(11+14+3 = 28) 
์„œ๋ฒ„์—์„œ ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์‚ฌ์šฉ์„ฑ์ด ๊ต‰์žฅํžˆ ๋–จ์–ด์ง€๊ฒŒ ๋˜๊ฒ ์ฃ ?

๋„ˆ๋ฌด ๋งŽ์ด ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค๋ฉด ์ผ๋ถ€ ์‚ฌ์šฉ์ž๋Š” ํ™”๋ฅผ ๋‚ด๋ฉฐ ์•ฑ์„ ์ œ๊ฑฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿคฏ

์ด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”? ์ด 14์ดˆ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ๋น ๋ฅด๋‹ค๊ณ  ๋ชจ๋“ ๊ฒŒ ์ข‹์€ ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค! 

๊ตฌ์กฐํ™”๋˜์ง€ ์•Š์€ ๋™์‹œ์„ฑ์€ ๋ชจ๋“  ์ž‘์—…์˜ ์™„๋ฃŒ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์ƒ์œ„ ์ฝ”๋ฃจํ‹ด์ด ์™„๋ฃŒ๋œ ํ›„์—๋„ 

ํ•˜์œ„ ์ฝ”๋ฃจํ‹ด์€ ๊ณ„์† ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์˜ˆ์ธกํ•˜์ง€ ๋ชปํ•œ ๊ฐ’ ๋˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋ฃจํ‹ด์€ ๋น„๋™๊ธฐ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ฐ˜ํ™˜๊ฐ’์— wait ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ์˜ ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ค๋ช…์„ ์œ„ํ•ด ์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์œผ๋กœ ์ด์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ‘ฉ‍๐Ÿ’ป ์ฝ”๋ฃจํ‹ด์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜์ง€?

์˜์กด์„ฑ ์ฃผ์ž… build.gradle

coroutine_version = "1.6.0"
//coroutine
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"

์ฝ”๋ฃจํ‹ด์˜ ์ฃผ์š” ์š”์†Œ:

  1. suspend :  suspend fun์œผ๋กœ ์„ ์–ธํ•œ ํ•จ์ˆ˜๋Š” ์ฝ”๋ฃจํ‹ด ๋‚ด์—์„œ๋งŒ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ค‘๊ฐ„์— ์ผ์‹œ ์ค‘์ง€๋  ์ˆ˜ ์žˆ๊ณ  ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ์ž‘๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. launch: ์ฝ”๋ฃจํ‹ด์„ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋น„๋™๊ธฐ ์ž‘์—…์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  3. async/await: ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ์œ„ํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.
  4. runBlocking: ์ฃผ๋กœ ํ…Œ์ŠคํŠธ๋‚˜ ๋ฉ”์ธ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ธ”๋กœํ‚น ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด Dispatchers:

์ฝ”๋ฃจํ‹ด์€ ํŠน์ • CoroutineDispatcher์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์šฉ๋„์— ๋งž๋Š” Dispatcher๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์—…ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  1. Dispatchers.Main: ์ฃผ UI ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋””์ŠคํŒจ์ฒ˜์ž…๋‹ˆ๋‹ค. UI ์—…๋ฐ์ดํŠธ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ์˜ ์ž‘์—…์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. Android์—์„œ๋Š” Dispatchers.Main์ด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์— ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. => UI ์ž‘์—…
  2. Dispatchers.IO :์ž…์ถœ๋ ฅ ์ž‘์—…(๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—… ๋“ฑ)์— ์ตœ์ ํ™”๋œ ๋””์ŠคํŒจ์ฒ˜์ž…๋‹ˆ๋‹ค. => ๋„คํŠธ์›Œํฌ๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…
  3. Dispatchers.Default: CPU ์ง‘์ค‘์ ์ธ ์ž‘์—…์— ์ตœ์ ํ™”๋œ ๋””์ŠคํŒจ์ฒ˜์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํฐ ๋ฆฌ์ŠคํŠธ์˜ ์ •๋ ฌ์ด๋‚˜ ๊ณ„์‚ฐ ์ž‘์—… ๋“ฑ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. => CPU ์ง‘์ค‘์ ์ธ ์ž‘์—…
  4. Dispatchers.Unconfined: ํŠน์ • ์Šค๋ ˆ๋“œ์— ์ข…์†๋˜์ง€ ์•Š๋Š” ๋””์ŠคํŒจ์ฒ˜์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ํ…Œ์ŠคํŠธ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. => ํ…Œ์ŠคํŠธ

ex. launch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋ฃจํ‹ด์„ ์‹œ์ž‘ํ•˜๊ณ , Dispatchers.IO์—์„œ ๋„คํŠธ์›Œํฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„, Dispatchers.Main์—์„œ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒฝ์šฐ

suspend fun fetchDataFromNetwork(): String { //suspend fun -> ์ฝ”๋ฃจํ‹ด๋‚ด์—์„œ๋งŒ ํ˜ธ์ถœ
    // ๋„คํŠธ์›Œํฌ ๋˜๋Š” DB์™€ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๊ฐ€์ •
    delay(1000)  // ๋น„๋™๊ธฐ ์ง€์—ฐ ํ•จ์ˆ˜๋กœ 1์ดˆ ์ง€์—ฐ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
    return "๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ ์™„๋ฃŒ"
}

fun updateUI(data: String) {
    println("UI ์—…๋ฐ์ดํŠธ: $data")
}

fun main() {
    runBlocking {  // ํ…Œ์ŠคํŠธ ๋ฐ ์˜ˆ์ œ ๋ชฉ์ ์œผ๋กœ runBlocking ์‚ฌ์šฉ
        launch(Dispatchers.IO) {
            // IO ์ž‘์—… ์ˆ˜ํ–‰
            val data = fetchDataFromNetwork()

            withContext(Dispatchers.Main) {
                // UI ์—…๋ฐ์ดํŠธ
                updateUI(data)
            }
        }
    }
}

 


๐Ÿ‘ฉ‍๐Ÿ’ป ์ฝ”๋ฃจํ‹ด ์ ์šฉํ•˜๊ธฐ

์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ดํ•ด๊ฐ€ ๋˜์—ˆ๋‹ค๋ฉด ์‹ค์ œ๋กœ ์šฐ๋ฆฌ ์ฝ”๋“œ์—์„œ ์ฝ”๋ฃจํ‹ด์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋” ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

(๋‚ด์šฉ์ด ๊น๋‹ˆ๋‹ค.. ์•„๋ž˜์— ์š”์•ฝ๋ณธ ์žˆ์Šต๋‹ˆ๋‹ค.)

  • withContext: ์ฃผ๋กœ ํ˜„์žฌ ์ฝ”๋ฃจํ‹ด์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋ฅผ ์ž„์‹œ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • CoroutineScope: ์ฝ”๋ฃจํ‹ด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ViewModelScope: Android ViewModel์— ๋‚ด์žฅ๋œ ์Šค์ฝ”ํ”„๋กœ, ViewModel์˜ ์ƒ๋ช… ์ฃผ๊ธฐ์— ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ withContext๋Š” ์ž‘์—…์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐ, CoroutineScope์™€ ViewModelScope๋Š” ์ฝ”๋ฃจํ‹ด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์ดˆ์ ์„ ๋‘ก๋‹ˆ๋‹ค.

1. withContext

  • ์„ค๋ช…: withContext๋Š” ์ฝ”๋ฃจํ‹ด์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋‹ค๋ฅธ Dispatcher๋กœ ์ฝ”๋ฃจํ‹ด์„ ์ด๋™ํ•˜์—ฌ ์ž‘์—…์„ ์‹คํ–‰ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
suspend fun fetchDataFromDatabase(): Data {
    return withContext(Dispatchers.IO) {
        // DB๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
        database.getData()
    }
}

 

2. CoroutineScope

  • ์„ค๋ช…: CoroutineScope๋Š” ์ฝ”๋ฃจํ‹ด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ์ œ์–ดํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํŠน์ • ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ์‹œ์ž‘๋œ ์ฝ”๋ฃจํ‹ด์€ ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ์ƒ๋ช… ์ฃผ๊ธฐ์— ์ข…์†๋ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ: Activity๋‚˜ Fragment์˜ ์ƒ๋ช… ์ฃผ๊ธฐ์™€ ์ฝ”๋ฃจํ‹ด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๋™๊ธฐํ™”ํ•˜๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
class MyActivity : AppCompatActivity(), CoroutineScope by CoroutineScope(Dispatchers.Main) {
    override fun onDestroy() {
        super.onDestroy()
        cancel() // ๋ชจ๋“  ์ฝ”๋ฃจํ‹ด ์ทจ์†Œ
    }

    fun loadData() {
        launch {
            // ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋กœ์ง
        }
    }
}

 

 

3. ViewModelScope

  • ์„ค๋ช…: ViewModelScope๋Š” Android์˜ ViewModel๊ณผ ์—ฐ๊ฒฐ๋œ ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„์ž…๋‹ˆ๋‹ค. ViewModel์ด ํด๋ฆฌ์–ด๋  ๋•Œ ํ•ด๋‹น ์Šค์ฝ”ํ”„ ๋‚ด์˜ ๋ชจ๋“  ์ฝ”๋ฃจํ‹ด๋„ ์ž๋™์œผ๋กœ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋‚˜ ํ•„์š” ์—†๋Š” ์ž‘์—…์˜ ์‹คํ–‰์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œViewModel ๋‚ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • kotlinCopy code class MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { // ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋กœ์ง } } }
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            // ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋กœ์ง
        }
    }
}

 

async  await

async์™€ await๋Š” ์ฝ”๋ฃจํ‹ด์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋™์‹œ์— ์‹œ์ž‘ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์•„์„œ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • async: ์ด ํ•จ์ˆ˜๋Š” ์ฃผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. async๋กœ ์‹œ์ž‘๋œ ์ฝ”๋ฃจํ‹ด์€ Deferred ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋‚˜์ค‘์— ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • await: Deferred ๊ฐ์ฒด์—์„œ ์‹ค์ œ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ํ•ด๋‹น ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ํ˜„์žฌ์˜ ์ฝ”๋ฃจํ‹ด ์‹คํ–‰์„ ์ผ์‹œ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ:

suspend fun fetchData(): Deferred<String> = coroutineScope {
    async {
        delay(1000)  // 1์ดˆ ๋™์•ˆ ์ง€์—ฐ
        "Data Fetched"
    }
}

suspend fun main() {
    val deferredData: Deferred<String> = fetchData()
    
    println("Doing some other work...")
    
    val data: String = deferredData.await() // ์—ฌ๊ธฐ์—์„œ ์ฝ”๋ฃจํ‹ด์€ fetchData์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
    println(data)  // "Data Fetched"๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
}

 

OnCleared

ViewModel ๋‚ด๋ถ€์—์„œ ์ฝ”๋ฃจํ‹ด์„ ์‚ฌ์šฉํ•  ๋•Œ onCleared๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ์ž์› ํ•ด์ œ: ViewModel์ด ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ, ์ฆ‰ ๊ด€๋ จ๋œ UI ์ปดํฌ๋„ŒํŠธ(์˜ˆ: ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ)๊ฐ€ ํŒŒ๊ดด๋˜์—ˆ์„ ๋•Œ onCleared๋Š” ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋ฃจํ‹ด์„ ์ทจ์†Œํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์„ ์ค‘๋‹จํ•˜๊ณ  ๊ด€๋ จ ์ž์›์„ ํ•ด์ œํ•˜๊ธฐ ์œ„ํ•ด onCleared๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€: ์ฝ”๋ฃจํ‹ด์ด ๊ณ„์† ์‹คํ–‰๋˜๋ฉด์„œ ViewModel์ด ํŒŒ๊ดด๋œ ํ›„์—๋„ ์ฐธ์กฐ๊ฐ€ ์œ ์ง€๋  ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋ฃจํ‹ด์„ ์ ์ ˆํžˆ ์ทจ์†Œํ•จ์œผ๋กœ์จ ์ด๋Ÿฌํ•œ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ViewModel์—์„œ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ViewModelScope๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

Structured Concurrency

์ฝ”๋ฃจํ‹ด์€ Structured Concurrency, Unstructured Concurrency ๋‘ ๊ฐ€์ง€๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ์ค‘ Unstructured Concurrency๋ฅผ ์“ฐ๋ฉด ์˜ˆ์™ธ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด Structured Concurrency๋ฅผ ์จ์•ผํ•ฉ๋‹ˆ๋‹ค.์ด ๋ฌธ์ œ๋Š” CoroutineScope๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Structured Concurrency๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋ฃจํ‹ด์ด ์ž๋™์œผ๋กœ ์ทจ์†Œ๋˜์–ด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋”์šฑ ์•ˆ์ „ํ•˜๊ฒŒ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. CoroutineScope๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ์ ˆํ•œ CoroutineContext๋ฅผ ์„ค์ •ํ•˜๊ณ , launch๋‚˜ async๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Unstructured Concurrency๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 


๐Ÿ‘ฉ‍๐Ÿ’ป ์ฝ”๋ฃจํ‹ด ์š”์•ฝ!

์ง์ ‘ ํ•œ๋•€ ํ•œ๋•€ ํ”ผ๊ทธ๋งˆ๋กœ ์š”์•ฝํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค! ๐Ÿซ 

์ฝ”๋ฃจํ‹ด ์š”์•ฝ

 


๐Ÿ‘ฉ‍๐Ÿ’ป ๋งˆ์น˜๋ฉฐ

์ด๋ฒˆ ๊ธ€์€ ์ด์•ผ๊ธฐ๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์„œ ๋ฐฉ์ „๋˜์—ˆ์Šต๋‹ˆ๋‹ค...๐Ÿชซ

์—ญ์‹œ ์ง€์‹์€ ๊นŠ์–ด์งˆ์ˆ˜๋ก ์–ด๋ ค์šด ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค...! 

์˜ค๋Š˜ ํ•˜๋ฃจ ๋ชจ๋‘ ํ–‰๋ณตํ•œ ์‹œ๊ฐ„ ๋ณด๋‚ด์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ’›

 

๋‹ค์Œ ๊ธ€๋„ ๊ธฐ๋Œ€ ๋ถ€ํƒ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค:)๐Ÿค—

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!

 

โฌ‡๏ธ ์ง€๊ธˆ ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์Šคํ† ์–ด์—์„œ ํ‹ฐ๋Œ ๋‹ค์šด ๋ฐ›๊ธฐ
https://play.google.com/store/apps/details?id=com.team7.tikkle&hl=ko-KR

๐Ÿ“ฉ Contact : wjdcogus6@gmail.com
๐Ÿ“ฒ SNS : https://www.instagram.com/chaeehyuny/