Android 코루틴을 처음 접하면 launch와 async를 단순히 "비동기로 실행하는 함수" 정도로 이해하기 쉽습니다. 하지만 두 함수는 모두 코루틴 빌더(Coroutine Builder)이며, 목적과 사용 방식이 명확히 다릅니다.
이번 글에서는 먼저 코루틴 빌더란 무엇인지 간단히 짚고, launch와 async 각각의 개념과 사용법을 살펴본 뒤, 두 빌더의 차이를 정리해보겠습니다.
코루틴 빌더(Coroutine Builder)는 코루틴을 시작하는 함수입니다. 즉, suspend 함수나 비동기 로직을 실제로 실행 가능한 코루틴으로 만들어주는 역할을 합니다. 여러 코루틴 빌더가 있지만 이번 글에서는 launch, async에 대해 알아보겠습니다. 이 둘은 항상 CoroutineScope 안에서 사용됩니다.
viewModelScope.launch {
// 코루틴 시작
}
launch는 결과를 반환하지 않는 코루틴 빌더입니다. 단순히 어떤 작업을 비동기로 실행하고 끝내는 용도로 사용됩니다.
viewModelScope.launch {
delay(1000)
println("작업 완료")
}
launch는 실행 결과를 다른 로직에서 사용할 필요가 없는 경우에 적합합니다. UI 상태 업데이트, DB 저장, 로그 출력 등의 상황에서 보통 사용됩니다.
async는 결과를 반환하는 코루틴 빌더입니다. 실제 값은 바로 반환되지 않고, Deferred<T> 형태로 감싸져 반환됩니다.
val deferred = async {
repository.fetchUser()
}
async는 비동기 작업의 결과가 이후 로직에 반드시 필요할 때 사용하며, 병렬 처리에 적합합니다. 결과는 await 호출 시점에 흭득하기 때문에 async는 반드시 await와 함께 사용되어야 의미가 있습니다.
viewModelScope.launch {
val userDeferred = async { repository.fetchUser() }
val postDeferred = async { repository.fetchPosts() }
val user = userDeferred.await()
val posts = postDeferred.await()
_uiState.value = UiState(user, posts)
}
이처럼 여러 작업을 동시에 실행하고 결과를 조합해야 할 때 async가 강력한 역할을 합니다.
async를 단순히 launch처럼 사용하는 것은 잘못된 사용이며, 오히려 코드의 의도를 흐리게 만듭니다. 두 코루틴 빌더의 역할을 명확히 구분하면 코루틴 코드는 훨씬 읽기 쉽고 안전해집니다.
코루틴을 잘 쓰기 위한 핵심은 복잡한 문법이 아니라, 상황에 맞는 빌더를 선택하는 것입니다. 이 기준만 잘 기억해두어도 Android 비동기 코드를 다루는 감각이 한층 좋아질 것입니다.