
[Android] Kotlin Coroutine으로 비동기 처리하기
안드로이드 개발에서는 네트워크 요청, 데이터베이스 읽기/쓰기, 파일 처리 등 시간이 오래 걸리는 작업을 비동기적으로 처리해야 합니다.
과거에는 AsyncTask
또는 Thread
+ Handler
조합을 사용했지만, 현재는 Kotlin Coroutine을 이용한 방식이 가장 효율적인 방법으로 자리 잡았습니다.
이번 포스팅에서는 Coroutine이 무엇인지, 어떻게 사용하는지, 실전 예제까지 하나씩 알아보겠습니다.
1. Coroutine이란?
Coroutine(코루틴)은 비동기 작업을 간결하고 직관적으로 작성할 수 있도록 도와주는 Kotlin의 기능입니다.
쓰레드를 직접 관리하지 않고도, 여러 작업을 효율적으로 실행할 수 있습니다.
🔹 Coroutine의 주요 특징
- 비동기 처리: 네트워크 요청, 파일 I/O, 데이터베이스 작업 등을 쉽게 비동기로 실행
- 경량성: 수천 개의 코루틴을 실행해도 메모리를 거의 사용하지 않음
- 구조적 동시성:
CoroutineScope
를 통해 생명주기를 관리하여 불필요한 작업 종료 가능
2. Coroutine 설정하기
Coroutine을 사용하려면 build.gradle
파일에 의존성을 추가해야 합니다.
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
}
3. Coroutine 기본 사용법
🔹 코루틴 실행하기
코루틴을 실행하려면 CoroutineScope.launch
를 사용합니다.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L) // 1초 대기
println("Hello, Coroutine!")
}
println("Coroutine 실행 전")
}
<<실행결과>>
Coroutine 실행 전
(1초 후) Hello, Coroutine!
4. 안드로이드에서 Coroutine 사용하기
안드로이드에서는 lifecycleScope
또는 viewModelScope
를 사용하여 코루틴을 실행합니다.
이렇게 하면 액티비티 또는 뷰모델의 생명주기에 맞춰 자동으로 코루틴이 종료되므로, 메모리 누수를 방지할 수 있습니다.
🔹 lifecycleScope
사용 (Activity에서 실행)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch {
delay(1000L)
Log.d("Coroutine", "Hello, Coroutine!")
}
}
}
🔹 viewModelScope
사용 (ViewModel에서 실행)
class MainViewModel : ViewModel() {
fun fetchData() {
viewModelScope.launch {
val result = fetchDataFromNetwork()
Log.d("Coroutine", "결과: $result")
}
}
private suspend fun fetchDataFromNetwork(): String {
delay(2000L) // 네트워크 요청 시뮬레이션
return "데이터 로드 완료"
}
}
5. Coroutine에서 비동기 작업 실행하기
🔹 suspend
함수 사용
Coroutine에서 오래 걸리는 작업(네트워크, 데이터베이스 등)은 suspend
함수로 만들 수 있습니다.
suspend
함수는 Coroutine 내에서만 호출 가능하며, 일반 함수에서는 직접 호출할 수 없습니다.
suspend fun fetchData(): String {
delay(2000L) // 네트워크 요청 시뮬레이션
return "서버 응답 데이터"
}
6. withContext
를 이용한 IO 작업
네트워크 요청이나 데이터베이스 접근과 같은 무거운 작업은 Dispatchers.IO
에서 실행하는 것이 좋습니다.
📌 Dispatchers
종류
Dispatchers.Main
→ UI 작업 (기본)Dispatchers.IO
→ 네트워크, 데이터베이스 등 IO 작업Dispatchers.Default
→ CPU 연산이 집중된 작업
lifecycleScope.launch {
val data = withContext(Dispatchers.IO) { fetchData() }
Log.d("Coroutine", "결과: $data")
}
7. Coroutine과 Retrofit을 함께 사용하기
Retrofit을 사용할 때도 suspend
함수를 활용하여 코루틴을 적용할 수 있습니다.
🔹 Retrofit API 인터페이스
interface ApiService {
@GET("users")
suspend fun getUsers(): List<User>
}
🔹 ViewModel에서 네트워크 요청
class MainViewModel : ViewModel() {
private val apiService = RetrofitInstance.api
fun fetchUsers() {
viewModelScope.launch {
try {
val users = apiService.getUsers()
Log.d("Coroutine", "유저 리스트: $users")
} catch (e: Exception) {
Log.e("Coroutine", "네트워크 오류", e)
}
}
}
}
8. Coroutine 취소하기
Coroutine이 불필요해지면 cancel()
을 호출하여 취소할 수 있습니다.
val job = lifecycleScope.launch {
repeat(10) {
delay(500L)
Log.d("Coroutine", "반복: $it")
}
}
// 특정 시점에 취소
job.cancel()
마무리 정리
- Coroutine을 사용하면 안드로이드에서 비동기 작업을 쉽고 직관적으로 처리할 수 있습니다.
lifecycleScope
,viewModelScope
를 사용하여 메모리 누수를 방지할 수 있습니다.- 네트워크 요청이나 데이터베이스 작업은
Dispatchers.IO
에서 실행해야 성능이 최적화됩니다. - Retrofit과 함께 사용하면 깔끔한 네트워크 비동기 처리가 가능합니다.