일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Android 12
- 프로그래머스 알고리즘
- Android Jetpack
- Java
- 영어독립365
- coroutine
- Kotlin FCM
- WebView
- 습관만들기
- 코틀린 코루틴
- 안드로이드 카카오 로그인
- Android Navigation
- 알고리즘 자바
- Android 12 대응
- Android ProgressBar
- android recyclerview
- 안드로이드
- 66챌린지
- scope function
- MVP Architecture
- Kotlin
- Android ViewPager2
- Android
- 안드로이드 갤러리 접근
- 영어공부
- DataBinding
- Android WebView
- 카카오 알고리즘
- Android Interceptor
- OkHttp Interceptor
- Today
- Total
나미래 Android 개발자
[Android Coroutine] launch 제대로 이해하기 — 반환값 없는 비동기 작업의 정석 본문
[Android Coroutine] launch 제대로 이해하기 — 반환값 없는 비동기 작업의 정석
Moimeme Futur 2025. 8. 29. 12:38이 글은 마르친 모스카와의 ⟪코틀린 코루틴⟫ 책을 기반으로 작성하였습니다.
여러분은 코루틴을 사용하기 위해 어떤 방식으로 코루틴을 만들고 계신가요?
아마 비동기 처리를 효과적으로 하기 위해서 직접 스레드를 생성하지 않고, 자연스럽게 중단(suspend) 함수를 호출하면서 코루틴에서 처리하도록 하고 있을 겁니다.
그렇다면 질문 하나 드려볼게요.
코루틴을 생성할 때, 어떤 상황에서는 어떤 코루틴 빌더를 사용해야 하는지 답변할 수 있으신가요?
여기서 등장하는 개념이 바로 코루틴 빌더(Coroutine Builder) 입니다.
이번 글에서는 Kotlinx.coroutines 라이브러리에서 제공하는 코루틴 빌더 중, 가장 많이 사용되는 launch 함수를 집중적으로 살펴보겠습니다.
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
코루틴 빌더(Coroutine Builder)란? 🚀
시간이 오래 걸리는 작업을 비동기적으로 처리하고 싶을 때, 효율적으로 처리할 수 있는 도구가 코루틴입니다. 그리고 코루틴을 생성하는 도구가 바로 코루틴 빌더입니다.
머릿속에 개념이 그려지기 위해 비유를 들어보겠습니다.
- 우리가 살고 있는 지구 행성🌎(=일반 함수 행성) 은 중단(suspend) 이라는 개념이 없습니다.
- 반대로 코루틴 행성🪐은 중단 가능한 특별한 개념을 가지고 있습니다.
따라서 지구 행성에서 중단 가능한 작업을 사용하기 위해 코루틴 행성으로 작업을 보내려면 특별한 로켓🚀이 필요한데, 이 로켓이 바로 코루틴 빌더 입니다. 로켓 안에 중단 가능한 기능을 담아 코루틴 행성으로 쏘아 올려 처리 요청을 하는 것이죠.
코루틴 빌더의 종류
Kotlinx.coroutines 라이브러리에서는 대표적으로 세 가지 빌더를 제공합니다.
- launch
- async
- runBlocking
각 빌더는 목적과 특성이 다르기 때문에 상황에 맞게 선택해서 사용해야 합니다.
이번 글에서는 이 중에서 launch에 집중하겠습니다.
문제 상황(요구사항)
먼저 launch 함수를 이해하기 위해서 간단한 개발 요구사항을 이야기하겠습니다.
만약 여러분이라면 다음과 같은 상황에서 어떻게 개발을 할 것인지 생각하면서 읽으시면 코루틴 빌더 launch 함수를 더 깊게 이해하고 오랫동안 기억하실 수 있으실 것입니다.
시간이 오래 걸리는 작업을 스레드를 멈추지 않고 실행시켜야 합니다. 하지만 해당 작업의 최종 반환값을 직접 받아 다른 계산에 활용할 필요가 없는 경우 어떻게 효과적으로 비동기를 처리할 수 있을까요?
여기서 주요 요구사항은 다음과 같습니다.
- 시간이 오래 걸리는 작업을 코루틴을 이용해 비동기로 처리한다.
- 해당 작업의 최종 결과값으로 직접 계산이 필요하지 않다.
이런 작업은 반환된 값을 곧바로 UI나 다른 연산에 전달하지 않아도 되고, 실행 자체와 그 효과(사이드이펙트)가 중요한 것입니다.
따라서 이런 경우 가장 적절한 코루틴 빌더가 바로 launch 입니다.
launch 함수의 특성
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
- CoroutineScope 확장 함수
- CoroutineScope를 리시버로 받기 때문에, launch를 호출하려면 CoroutineScope가 필요합니다.
- 예: GlobalScope.launch { … }, viewModelScope.launch { … }
- suspend 고차 함수를 블록으로 받음
- block 파라미터에 넘기는 람다 내부는 중단 가능합니다.
- 즉. delay, withContext, suspend fun 등을 자연스럽게 호출할 수 있습니다.
- Job 반환
- launch는 Job을 반환합니다.
- 반환된 Job을 이용하면 취소, 대기(join), 상태 확인이 가능합니다.
launch 함수의 핵심 특징
- CoroutineScope 확장성
- CoroutineScope의 확장 함수이기 때문에 부모 스코프의 생명주기를 자동으로 따릅니다.
- 부모 스코프가 취소되면 launch로 실행된 자식 코루틴도 함께 취소됩니다.
- suspend 블록 실행 가능
- block 파라미터에 넘기는 람다 내부는 중단 가능하기 때문에, delay, withContext, suspend fun 등을 호출할 수 있습니다.
- 반환값 자체를 돌려주기보다는, 실행 과정에서 발생하는 side-effect에 적합합니다.
- Job 반환과 예외 전파
- launch는 Job을 반환하여 취소, 대기(join), 상태 확인을 제어할 수 있습니다.
- Job으로 생성된 코루틴에서 발생한 예외는 즉시 부모 스코프로 전파되어, viewModel이나 LifecycleScope 같은 UI 스코프에서 안정적으로 예외를 처리할 수 있습니다.
실제 사용 예시
간단한 콘솔 예시
fun main() {
println("Main Started")
GlobalScope.launch {
delay(1000L) // 시간이 오래 걸리는 작업
println("Coroutine Done")
}
println("Main Processing")
Thread.sleep(2000L) // 메인 스레드가 종료되지 않게 대기
println("Main Done")
}
// [출력 결과]
// Main Started
// Main Processing
// (1초 후)
// Coroutine Done
// (1초 후)
// Main Done
여기서 launch는 비동기 코루틴 실행을 담당합니다.
반환값이 필요하지 않기 때문에, 결과를 받아오는 코드는 없습니다.
⚠️주의
GlobalScope는 구조적 동시성이 깨지므로 실무에서는 사용하지 않는 것을 강력히 권장합니다.
예제에서만 편의상 사용했습니다.
실제 앱 개발에서는 viewModelScope, lifecycleScope 등을 사용하는 것을 권장합니다.
Android 실무 예시: 버튼 클릭 이벤트 트래킹 & 단일 데이터 처리
class ProfileViewModel(
private val analytics: Analytics,
private val repO: UserRepository
): ViewModel() {
fun onFollowClicked(targetUserId: String) {
// UI는 즉시 반응
// 비동기 트래킹은 launch로 처리 (값 불필요)
viewModelScope.launch {
analytics.logEvent(
"follow_click",
mapOf("target" to targetUserId)
)
}
}
fun refreshProfile() {
// 단일 데이터 호출 후 UI 상태로 반영
viewModelScope.launch {
val profile = withContext(Dispatchers.IO) { repo.fetchProfile() }
_uiState.value = UiState.Success(profile)
}
}
}
어떠신가요? 위 코드에서 launch가 어떻게 왜 사용되었는지 머릿속에 그려지시나요?
이 코드는 실무에서 흔히 볼 수 있는 예시 코드라고 생각됩니다.
위와 같은 상황에서 다들 자연스럽게 launch를 사용하시고 있었을 것 같은데요. 여기까지 글을 읽어주신 여러분은 이제 코루틴 빌더인 launch를 어떤 상황에서 사용해야하는 지 알고 사용할 수 있으실 겁니다.
정리
launch는 안드로이드 개발에서 가장 자주 사용되는 코루틴 빌더입니다. 특히 반환값이 필요하지 않고, 실행 과정에서 외부 상태나 환경에 변화를 주는 작업(사이드이펙트)에 적합합니다.
핵심 포인트를 다시 정리하면 다음과 같습니다.
launch의 특징
- 값을 직접 반환하지 않는 비동기 작업에 최적화
- Job을 반환하여 취소, 대기(join), 상태 확인이 가능
- CoroutineScope에 묶여 구조적 동시성 보장
- 발생한 예외는 부모 스코프로 전파되어 안정적으로 처리 가능
언제 사용해야 할까?
- 로그 기록, 이벤트 트래킹, 캐시 저장 등 결과값이 필요 없는 비동기 작업
- 단일 데이터 API 호출 후 UI 상태에 반영할 때
- 장시간 실행되는 작업을 취소 가능하게 관리할 때
- 로그아웃처럼 여러 사이드이펙트를 한 번에 처리하는 경우
주의사항
- GlobalScope 사용은 지양하고, viewModelScope, lifecycleScope와 같이 생명주기에 맞는 스코프 사용을 지향
이제 “launch를 어떤 상황에 쓰나요?”라고 질문을 받아도 자신 있게 답할 수 있을 겁니다!
'안드로이드 > Coroutine' 카테고리의 다른 글
[Android Coroutine] async 제대로 이해하기 — 반환값 있는 비동기 작업의 정석 (0) | 2025.09.07 |
---|---|
코틀린 supervisorScope로 안전한 병렬 처리하기 - 코루틴 스코프 함수 완벽 가이드 (1) | 2025.08.18 |
코틀린 coroutineScope 사용법과 예제 - 코루틴 스코프 함수 완벽 가이드 (3) | 2025.08.07 |
[Android Coroutine] 구조적 동시성을 완성하는 마지막 퍼즐: 코루틴 취소(Cancellation) (0) | 2025.05.03 |
[Android Coroutine] 구조적 동시성 쉽게 이해하기 – Job과 launch의 관계 (0) | 2025.05.01 |