
(๐จ ์ค๋ฅ ์ ์ ) ๐ค 2025๋ ๋์๋ ๊ฐ๋ฐ์๋ค์ ์ฝ๋ฃจํด ์์ธ ์ฒ๋ฆฌ ๋๋ฌธ์ ๋ฐค์๊ฐ? ๐จ (2025ํ๋ ๋ ์๋๋ก์ด๋ ํ๊ตฌ์์ญ ๋ฌธ์ ํ์ด)
๋ณธ๋ฌธ
์ด ๊ธ์ 2025 ์๋๋ก์ด๋ ํ๊ตฌ ์์ญ์ ๋์จ ๋ฌธ์ ์ค ์ผ๋ถ๋ฅผ ํด์ํ๋ ๊ธ์ ํํ๋ก ์์ฑํฉ๋๋ค. ๋ฌธ์ ์ ์ฒด๋ฅผ ๋ด์ง ์๊ณ , ์ค์ํ ํด์ค์ ์์ฑํฉ๋๋ค.
์ ์
24.12.11 ํด์์ ์ค๋ฅ๊ฐ ์์ผ๋ฉฐ, ์ฝ๋ ๊ฒ์ฆ ๊ณผ์ ์์ ์ค๋ฅ๋ฅผ ํ์ธํ์ฌ ์์ ํฉ๋๋ค.
๋๊ธ๋ก ์ค๋ฅ๊ฐ ์๋ค๊ณ ์๋ ค์ฃผ์ Larry, ์ก์ค์๋ ๊ฐ์ฌํฉ๋๋ค.
์๋๋ก์ด๋ ํ๊ตฌ ์์ญ ํ๊ธฐ ๊ธ
- 2025ํ๋ ๋ ์๋๋ก์ด๋ ํ๊ตฌ์์ญ - link
- 2025ํ๋ ๋ ์๋๋ก์ด๋ ํ๊ตฌ์์ญ์ ์ค๋นํ๋ฉฐ(๊ฒฝ์๋ ์์ฑ) - link
์ด๋ค ๋ฌธ์ ์ผ๊น?
์ฝ๋ฃจํด Exception ๋ฐ์ ์ ์์ธ ๋ฒ์๋ฅผ ๋ฌผ์ด๋ณด๋ ์ง๋ฌธ์ ๋ํ ํด์์ ๋ด๋ ๊ธ์ด๋ค.
๋๋ต ์ ์ด๋ณด๋ฉด
- ์ต์์ Job A๋ viewModelScope.launch๋ก ์์ฑ๋๊ณ ๋ด๋ถ์์ B, C๋ฅผ ์์ฑํ๋ค.
- B์์๋ coroutineScope ๋ด์์ D, E๋ฅผ ์์ฑํ๋ค.
- C์์๋ withContext(Dispatchers.IO) ๋ด์์ F๋ฅผ ์์ฑํ๋ค.
๋ชจ๋ Job์ด Finish ๋์๋ค๊ณ ๊ฐ์
A-F๊น์ง ๋ชจ๋ Job์ด ๋ฆฌํด๋๋ค๋ ์ฌ์ค๊ณผ ๋ชจ๋ Job์ด ๋์ ์๋ฃ๋์์ ๋๋ฅผ ๊ฐ์ ํ๋ค.
์ด ๋ถ๋ถ์ ๋ํ ๊ธ์ ์ด๋ฏธ ๊ณผ๊ฑฐ์๋ ์์ฑํ์ด์ ๋งํฌ๋ฅผ ์ถ๊ฐํด๋๊ฒ ๋ค.
์ด ๋ ๊ฐ์ ๊ธ์ ์ดํดํ๋ค๋ฉด ์ฌ์ค ํด์ํ ํ์๋ ์์ง๋ง, ์๋ก์ด ๋ง์์ผ๋ก ๊ธ์ ์ ์ด๋ณธ๋ค.
์ด ๊ธ์์๋
- 2025 ์๋๋ก์ด๋ ํ๊ตฌ ์์ญ์ ๋์จ ๋ฌธ์ ์ผ๋ถ๋ฅผ ์ ๋ฆฌํ๋ค.
- Job์ ๋ํ ์ดํด๊ฐ ํ์ํ๋ค.
๋ฌธ์ ์ ํด์
๋ชจ๋ ์คํ์์ Job์ ๊ฐ์ง๋ ค๋ฉด launch {}๋ฅผ ํตํด ์๋ก์ด ์์
์ ์คํํด์ผ ํ๋ค๋ ์ ์ด๋ค.
async๋ DeffDeferred T๋ฅผ ๋ฆฌํดํ๊ธฐ์ ์ ์ ํ์ง ์์ ์คํ์ ํด๋นํ๊ธฐ์ ์ฝ๋๋ก ์์ฑํ๋ฉด ์๋์ ๊ฐ๋ค.
// A์ ์คํ
viewModelScope.launch {
// B์ ์คํ
launch {
coroutineScope {
// D์ ์คํ
launch { }
// E์ ์คํ
launch { }
}
}
// C์ ์คํ
launch {
withContext(Dispatchers.IO) {
// F์ ์คํ
launch { }
}
}
}
์ด ๋ฌธ์ ๋ฅผ ํด์ํ ๋ ์ฃผ์ํ ์ ์ด ํ๋ ์๋ค.
Coroutine builder๋ก ์คํํ๋ ๊ฒฝ์ฐ ๋ถ๋ชจ์ CoroutineContext๋ ํ์(์์) ๋ชจ๋ ์์๋ฐ๋ ๊ฒ์ด ์๋๋ผ๋ ์ ์ด๋ค. ์ฝ๋๋ฅผ ์ถ์ ํ๋ฉด fold๋ฅผ ํตํด ํฉ์ฐํ๋ค.
๋จ, Job์ ์์๋ฐ์ง ์๋๋ฐ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ ๋ฏธ๋์ด์ ์ค๋ช ์ด๋ค.
๋ง์ฝ Job์ด ์์๋๋ค๋ฉด, ๋ถ๋ชจ ์ฝ๋ฃจํด์ Job์ด ์ทจ์๋ ๋ ์์ ์ฝ๋ฃจํด๋ ํจ๊ป ์ทจ์๋ฉ๋๋ค. ์ด๋ ๊ฐ ์ฝ๋ฃจํด์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค. ๊ฐ ์ฝ๋ฃจํด์ด ๋ ๋ฆฝ์ ์ธ Job์ ๊ฐ์ง๋๋ก ํจ์ผ๋ก์จ, ์ฝ๋ฃจํด์ ์ทจ์์ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ๋ฅผ ๋์ฑ ์ ์ฐํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค.
๊ฒฐ๊ตญ ํ์ํ ๊ฒ๋ง ํฉ์ฐํ๊ณ ์นํํ ์ ์์ผ๋ฉฐ, Job์ ์์ธ๋ก ์์๋ฐ์ง ์๋๋ค.
ํจ์ ๋ ์ฐพ์๋ณด์.
์ด ๋ฌธ์ ์๋ 2๊ฐ์ง ํจ์ ์ด ์๋ค. ๋ฐ๋ก coroutineScope๊ณผ withContext(Dispatchers.IO)์ด๋ค.
์ด ์ฝ๋์์๋ ์ฌ์ค ์๋ฌด๋ฐ ์๋ฏธ๊ฐ ์๋ค. ์ด์ฐจํผ launch {}๋ฅผ ํตํด ์ฝ๋๋ฅผ ์คํํ๊ธฐ ๋๋ฌธ์ blocking์ ๋ง๋๋ coroutineScope๊ณผ withContext(Dispatchers.IO) ์ฝ๋์ ์ฌ์ฉ์ ์๋ฏธ๊ฐ ์๊ณ ํจ์ ์ ๋ง๋ค๊ธฐ ์ํ ์ฝ๋ ์ค๋ช
์ด๋ผ๋ ์ ์ด๋ค.
Job?
Job์๋ ํฌ๊ฒ 2๊ฐ ์๋ค.
๊ทธ๋ฅ Job - link๊ณผ SupervisorJob - link์ ๊ฐ์ง๋ค.
์ด ๋์ ๋ฑ ํ๋์ ์ฐจ์ด๊ฐ ์๋๋ฐ, ํ์ Job์์ ๋ฐ์ํ๋ Exception ์ผ์ด์ค๋ก ์ธํด ๋ถ๋ชจ๊ฐ ์ํฅ์ ๋ฐ๋๊ฐ ์๋๊ฐ์ด๋ค.
์ด์ ๊ธ์์๋ ์์ฑํ์ง๋ง Kotlin Coroutines Exception ์ํฅ๋ ์์๋ณด๊ธฐ๋ฅผ ์ค์ด๊ธฐ ์ํด์๋ SupervisorJob์ ํ์ฉํ๋ ๊ฒ์ด ์ ํฉํ๋ค.
๋คํํ android viewModelScope์ SupervisorJob์ ๊ธฐ๋ณธ์ผ๋ก ํ์ฉํ๊ณ ์๋ค.
Job์ ๋ผ์ดํ ์ฌ์ดํด๋ ๊ฐ์ง๊ณ ์๋๋ฐ ์๋์ ๊ทธ๋ฆผ๊ณผ ๊ฐ๋ค.

์ด ๋ถ๋ถ์ ๊ผญ ๊ธฐ์ตํ ์ด์ ๋ ์์ง๋ง cancel/fail ์ฒ๋ฆฌ ์ Cancelled ์ํ๋ก ๋ณ๊ฒฝ๋๋ค๋ ์ ์ด ์ค์ํ ๋ถ๋ถ์ด๋ค.
์ด๊ฑธ ์์ง ์๋๋ผ๋ ์ฝ๋ฃจํด์์๋ exception ๋ฐ์ ์ runCatch๋ง ์ ๊ฑธ์ด๋ ๋ฌธ์ ๊ฐ ์์ผ๋ฉฐ, ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ฌ์๋ ๊ฐ๋ฅํ๋ค๋ ์ ์ด ์ค์ํ ํฌ์ธํธ ์๋๊น ์ถ๋ค.
๋ฌธ์ ํด์ ์ ์ .
์ ๋ด์ฉ์ผ๋ก ์ ์ ์๋ ์ฌ์ค์ ๊ทธ๋์ ์ํฅ๋๊ฐ ์ด๋๊น์ง ์ ํ๋ ๊น์ด๋ค.
// A์ ์คํ
viewModelScope.launch {
// B์ ์คํ
launch {
coroutineScope {
// D์ ์คํ
launch { }
// E์ ์คํ
launch { }
}
}
// C์ ์คํ
launch {
withContext(Dispatchers.IO) {
// F์ ์คํ
launch { }
}
}
}
์ด ์ฝ๋๋ ์ด๋์์ ์ค๋ฅ๊ฐ ๋๋ viewModelScope.launch {}์ธ A๊ฐ ์ข ๋ฃ๋๋ค.
๊ทธ๋ ๊ธฐ์ ๋ฌธ์ ์ ๋์จ ๋ต๋ณ์ ์ ๋ต์ด ์์ ์ ์๋ค.
๊ทธ๋๋ ๊ถ๊ธํ์์
๊ทธ๋ผ ์ ์ฝ๋์์ ์ผ๋ถ์ ์์ ์ Job()๋ก ๋ค์ ๋ณ๊ฒฝํ๋ฉด ์ํฅ์ ์ด๋ป๊ฒ ๋ฌ๋ผ์ง๊น?
์์ ์ ์๋ ์ฝ๋์ B์ ์์
์ Job()์ผ๋ก ์นํํ๋ฉด ์ด๋ค ์ผ์ด ๋ฒ์ด์ง๊น?
// A์ ์คํ
CoroutinesScope(SupervisorJob()).launch {
// B์ ์คํ
launch(Job()) { // Job์ผ๋ก ๋ณ๊ฒฝ
// D์ ์คํ
launch { throw Exception("exception") }
// E์ ์คํ
launch { }
}
// C์ ์คํ
launch {
// F์ ์คํ
launch { }
}
}
๊ฐ๋จํ๋ค.
- A๋ ๊ตฌ์กฐํ๊ฐ ๊นจ์ง B์ ์ํฅ์ ๋ฐ์ง ์์ผ๋ฉฐ, C ๋ด๋ถ์์ ๋ฐ์ํ ์ค๋ฅ ์ญ์ ์ํฅ๋ฐ์ง ์๋๋ค.
- B๋ ์๋ก์ด Job์ ์์ฑํ์๊ธฐ์ A์ ๋ฌด๊ดํ๋ฉฐ D/E์ ์์ ์คํจ์ ๋ํ ์ํฅ ๋ฐ๋๋ค.
- C๋ F์์ ๋ฐ์ํ๋ ์ค๋ฅ์ ์ํฅ๋ฐ์ง ์๋๋ค.
- C๋ ์๋ก์ด Job์ ์์ฑํ B์์ ๋ฐ์ํ ์ค๋ฅ์ ๋ํ ์ํฅ ๋ฐ์ง ์๋๋ค.
์ด๋ฐ ์ด์ ๋ ์ ๋ฏธ๋์ด์์ ์ค๋ช ํ Job์ ์์ธ ์ค๋ช ์์ ์ถฉ๋ถํ ์ ๋์จ๋ค.
Job ๋์ ์ฌ์ฉํ ์ ์๋ ์์ ํ ๋ฐฉ๋ฒ์
supervisorScope์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ผ๋ ์ฐธ๊ณ ํ์ฌ ์ฌ์ฉํ์๊ธธ
// A์ ์คํ
CoroutinesScope(SupervisorJob()).launch {
// B์ ์คํ
supervisorScope {
launch { // Job์ผ๋ก ๋ณ๊ฒฝ
// D์ ์คํ
launch { throw Exception("exception") }
// E์ ์คํ
launch { }
}
}
// C์ ์คํ
launch {
// F์ ์คํ
launch { }
}
}
๊ฐ๋จํ ์๋ฆฌ ์ ์ ํฌํจ
๋ด๋ถ ์ฝ๋๋ ๋ฌด๊ดํ๊ฒ ์๋์ ๊ฐ๋ค.
val a = viewModelScope.launch {
// ์ฌ๊ธฐ์ ์ค๋ฅ๊ฐ ๋๊ฑฐ๋
}
val b = viewModelScope.launch {
// ์ฌ๊ธฐ์ ์ค๋ฅ๊ฐ ๋๊ฑฐ๋
}
์์ ๊ฐ์ด a/b์ ์ต์์ viewModelScope์ ๋ํ launch {}๋ฅผ ์คํํ ๋๋ a/b ์ค ์ด๋ ๊ณณ์์ exception์ด ๋ฐ์ํ๋๋ผ๋ ์๋ก ์ํฅ ๋ฐ์ง ์๋๋ค.
์ด์ ์ ์ค๋ฅ๋ฅผ ๋ฒํ ์ด์ ๋ ์๋์ ๊ฐ์ ๋ด๋ถ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋น์ฐํ๊ฒ๋ launch์ ์์ viewModelScope.launch {}๋ฅผ ๋ถ๋ชจ๋ก ๊ฐ์ง๊ณ ์์์๊ฑฐ๋ผ๊ณ ์ฐฉ๊ฐํ ๋ถ๋ถ์ด๋ค.
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
override fun childCancelled(cause: Throwable): Boolean = false
}
์ง๊ธ ํ์ฌ์ Job๊ณผ Parent Job์ ๋ชจ๋ ๊ฐ์ง๊ณ ์ํตํ๋ค๋ ์ ์ ์ ์ ์๋ค.
private val _parentHandle = atomic<ChildHandle?>(null)
internal var parentHandle: ChildHandle?
get() = _parentHandle.value
set(value) { _parentHandle.value = value }
override val parent: Job?
get() = parentHandle?.parent
๋ง๋ฌด๋ฆฌ
๊ฐ๋จํ๊ฒ 2025 ์๋๋ก์ด๋ ํ๊ตฌ์์ญ์ Exception ์ ํ์ ๋ํด ์ ๋ฆฌํ์๋ค.
์ด ๋ฌธ์ ๋ฅผ ์ ์ ์๋ ๊ฒ์
- Job์
cancel/fail๋ฐ์ ์ ํ์ฌ ์ํ๋ฅผCancelled์ฒ๋ฆฌํ๋ค. - Job์ ํ์ context์ ์ ๋ฌ๋์ง ์์ง๋ง Parent.job์ ํ์ Job์์๋ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ค.
- SupervisorJob๊ณผ Job์ ์ค๊ฐ์ ํผ์ฉํด์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ Job ๋ถ๋ถ์ ๋ชจ๋ ์ข ๋ฃ ์ฒ๋ฆฌํ๋ค.
- launch๋ก ์คํํ ๊ฒฝ์ฐ return ๊ฒฐ๊ณผ๋ Job์ด ๋๋ค.
Job๊ณผ SupervisorJob์ ์ค์์ฑ์ ์ดํดํ ์ ์๋ ๊ฐ๋จํ ๋ฌธ์ ์ ๋๋ค.
์ ์ ํ๋ฉด์
AI์๊ฒ ์ง๋ฌธ์ ๋ค ๋จ๊ฒจ๋ณด์๋๋ฐ ์๋ก ๋ค๋ฅธ ๋ต๋ณ์ ์ค๋ค.
AI์ ์๋ต์ด 100% ๋ต์ ์๋๊ฒ ์ง๋ง ์ผ๋ถ ๋ง๋ค๊ณ ๊ฐ์ ํ๊ณ ์ด์ผ๊ธฐํ๊ณ , ๋ด๊ฐ ์๊ณ ์๋ ๋ด์ฉ์ ์ ๋ฌํ๋ฉด์ ์ค๋ฅ๊ฐ ์๊ฒผ๋ค. ์ ๋นํ ์๋ฐํ๊ฒ ์ฌ์ฉํ๋ฉด ์ ์ฉํ ๋๊ตฌ์์ ๋ง๋ค.
๊ฒฐ๊ตญ ์ฝ๋ ๊ฒ์ฆ์ ํตํด ์๋ชป๋์๋ค๋ ๊ฑธ ๋ฐ๊ฒฌํ๊ณ ๋์ ์์ ์ ํ์ง๋ง ์ฌ๋ฏธ์๋ ๋ฌธ์ ์์ ๋ง๋ค.
์ค์ ๊ฐ๋ฐํ ๋๋ ์ด๋ ๊ฒ ์ฌ์ฉํ๋๋ผ๋ runCatch๋ฅผ ํญ์ ๋ฌ๊ณ ์ฌ์ฉํ๋ ํฌ๊ฒ ๋ฌธ์ ๋ฅผ ๋๋ผ์ง ๋ชปํ์๋ค.
์ฝ๋ฃจํด ์์ธ ์ ํ์ ๋ํ ์์ ์ถ๊ฐ
์ฐํ ์ฝ ํฌ๋ฃจ ์ค๋ฅ์ด๋์ ์ฝ๋ฃจํด ์์ธ ์ฒ๋ฆฌ ์์์ ์ถ๊ฐํฉ๋๋ค.
Comments