[Kotlin] Coroutine이란?

hyenni·2025년 3월 1일

Kotlin

목록 보기
2/2
post-thumbnail

이전 글에서는 Kotlin의 Retrofit에 대해서 정리해봤습니다.

Kotlin | Retrofit 글 보러가기




안드로이드에서 비동기 작업을 처리할 때 Thread, AsyncTask 등을 사용하면 코드가 복잡해지고 관리하기 어려워집니다. 이를 해결하기 위해 Kotlin에서는 Coroutine 이라는 강력한 비동기 프로그래밍 기법을 제공합니다.

이번 글에서는 코루틴의 개념, 기본 사용법을 알아보겠습니다.



Coroutine이란?

  • 코루틴은 가벼운 스레드로, 기존의 스레드보다 효율적으로 비동기 작업을 처리할 수 있다.

coroutine의 특징

  • 비동기 코드 작성 단순화 -> 콜백 지옥 해결
  • 경량 스레드 -> 스레드보다 적은 리소스 사용
  • 자동 일시 중단 및 재개 가능 -> suspend 함수 사용
  • 메모리 관리가 용이 -> viewModelScope,LlifecycleScope 사용


왜 코루틴을 사용할까?

  • 기존 Thread, AsyncTask 대비 코드가 간결해짐
  • 백그라운드에서 네트워크 요청을 수행한 뒤, 메인 스레드에서 UI 업데이트 가능
  • 비동기 로직을 순차적인 코드처럼 작성할 수 있음


코루틴 기본 개념

1. suspend 키워드

suspend 키워드는 코루틴에서 실행될 수 있는 함수이다.

interface Api {
    @GET("public/ticker/ALL_KRW")
    suspend fun getCurrentCoinList() : CurrentPriceList
}
  • suspend 함수는 반드시 코루틴 내부에서 호출해야한다.

2. launch vs async

코루틴을 실행할 때 launchasync 두 가지 방식이 있다.

  • launch : 결과를 반환하지 않음 ( 단순 실행 )
viewModelScope.launch {
    val result = netWorkRepository.getCurrentCoinList()
    println("데이터 로드 완료: $result")
}
  • async : 결과를 반환함 ( Deferred<T> 사용 )
viewModelScope.launch {
    val result = async { netWorkRepository.getCurrentCoinList() }
    println("결과 대기 후 출력: ${result.await()}")
}



3. 코루틴을 활용한 Retrofit 요청

1. Repository에서 API 호출

class NetWorkRepository {
    private val client = RetrofitInstance.getInstance().create(Api::class.java)

    suspend fun getCurrentCoinList() = client.getCurrentCoinList()
}
  • suspend fun을 사용하여 콜백 없이 네트워크 요청 가능
  • viewModelScope.launch로 ViewModel이 살아있는 동안만 실행

2. ViewModel 에서 코루틴으로 API 호출

class SelectViewModel : ViewModel() {

    private val netWorkRepository = NetWorkRepository()
    private lateinit var currentPriceResultList : ArrayList<CurrentPriceResult>

    // 데이터변화를 관찰 LiveData
    private val _currentPriceResult = MutableLiveData<List<CurrentPriceResult>>()
    val currentPriceResult : LiveData<List<CurrentPriceResult>>
        get() = _currentPriceResult

    fun getCurrentCoinList() = viewModelScope.launch {

        val result = netWorkRepository.getCurrentCoinList()
        currentPriceResultList = ArrayList()

        for(coin in result.data) {
            try{
                val gson = Gson()
                val gsonToJson = gson.toJson(result.data.get(coin.key))
                val gsonFromJson = gson.fromJson(gsonToJson, CurrentPrice::class.java)
                val currentPriceResult = CurrentPriceResult(coin.key, gsonFromJson)

                currentPriceResultList.add(currentPriceResult)

            }catch (e: java.lang.Exception){
                Timber.d(e.toString())
            }
        }
        _currentPriceResult.value = currentPriceResultList
    }
}
  • ViewModelScope.launch로 UI가 살아있는 동안만 코루틴 유지
  • try-catch를 이용한 네트워크 에러 처리 가능
  • 데이터를 받아온 후 LiveData를 업데이트하여 UI 갱신


Coroutine의 스레드 관리 (Dispatcher)

코루틴은 Dispatcher를 사용해 백그라운드와 메인 스레드를 조정할 수 있다.

launch(Dispatchers.Main) { }  // 메인(UI) 스레드 (기본값)
launch(Dispatchers.IO) { }    // 네트워크, DB 작업 (백그라운드)
launch(Dispatchers.Default) { }  // CPU 집중 작업

-> 네트워크 요청은 IO, UI 업데이트는 Main


viewModelScope.launch(Dispatchers.IO) {
    val result = netWorkRepository.getCurrentCoinList()
    withContext(Dispatchers.Main) {
        _currentPriceResult.value = result  // UI 업데이트는 메인 스레드에서!
    }
}

-> withContext(Dispatchers.Main)을 사용하면 백그라운드 작업 후 UI 업데이트 가능



정리

  • 코루틴은 비동기 작업을 간결하게 작성할 수 있는 기능이다.
  • suspend fun을 활용해 중단/재계 가능하다.
  • lanunch vs async : 결과 반환 여부에 따라 선택
  • viewModelScope를 사용해 메모리 관리를 최적화한다.
  • Retrofit과 함께 사용하면 네트워크 요청을 쉽게 처리 가능하다.
profile
안녕하세요

0개의 댓글