본문 바로가기

안드로이드/Asynchronous

[안드로이드] 코루틴

코루틴(Coroutine)

코루틴은 Kotlin에서 지원하는 비동기 처리 기술이다.

 

코루틴은 장기 실행 작업을 관리하는데 도움을 주며, 기능은 다음과 같다.

 

  • 경량( Lightweight ):  코루틴은 실행 중인 스레드를 차단하지 않는 정지(suspend)를 지원하므로 단일 스레드에서 많은 코루틴을 실행할 수 있고, 동시 작업을 진행하면서 차단보다 메모리를 절약할 수 있다.
suspend fun func()

 

  • 메모리 누수 감소: 구조화된 동시 실행을 사용하여 범위 내에서 작업을 실행한다.
    • CoroutineScope에서만 새 코루틴을 시작할 수 있다.
  • 기본 제공 취소 지원: 취소는 실행 중인 코루틴 계층 구조를 통해 자동으로 전파된다.
    • 사용하지 않는 코루틴을 끝낼 수 있는 기능이다.
  • Jetpack 통합: 많은 Jetpack 라이브러리에 코루틴을 완전히 지원하는 확장 프로그램이 포함되어 있고, 일부 라이브러리는 자체 코루틴 범위도 제공한다.
    • Jetpack에서 코루틴 사용을 밀어주고 있음

 

코루틴의 구성 요소

  • CoroutineScope: 하나 이상의 관련 코루틴을 관리, 모든 코루틴은 해당 범위 내에서 실행해야 한다.
    • 종류: CoroutineScope, LifecycleScope, ViewModelScope
  • launch: 코루틴을 만들고 함수 본문의 실행을 해당하는 디스패처에 전달하는 함수
  • Dispatcher: 코루틴이 어느 스레드에서 실행될지 결정하는 역할
    • Dispatchers.Main : UI와 상호작용하고 빠른 작업을 실행하기 위해서만 사용해야 한다.
    • Dispatchers.IO : 메인 스레드 외부에서 디스크 또는 네트워크 I/O를 실행하도록 최적화되어 있다.
    • Dispatchers.Default : CPU를 많이 사용하는 작업을 실행하는데 최적화되어 있다. (list sort, Json parsing..)

 

사용 방법

 

일반적으로 코루틴의 사용법은 다음과 같다.

CoroutineScope(Dispatchers.IO).launch {
	...
}

 

이렇게도 사용할 수 있는데

CoroutineScope.launch {...}

이때의 스레드는 메인스레드로 기본 설정된다.

 

예제

구글 공식문서의 예제로 살펴보는 코루틴

https://developer.android.com/kotlin/coroutines?hl=ko#executing-in-a-background-thread

 

Android의 Kotlin 코루틴  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android의 Kotlin 코루틴 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 코루틴은 비동기적으로 실행되는

developer.android.com

 

Repository.kt

class LoginRepository(private val responseParser: LoginResponseParser) {
    private const val loginUrl = "https://example.com/login"

    // Function that makes the network request, blocking the current thread
    fun makeLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {
        val url = URL(loginUrl)
        (url.openConnection() as? HttpURLConnection)?.run {
            requestMethod = "POST"
            setRequestProperty("Content-Type", "application/json; utf-8")
            setRequestProperty("Accept", "application/json")
            doOutput = true
            outputStream.write(jsonBody.toByteArray())
            return Result.Success(responseParser.parse(inputStream))
        }
        return Result.Error(Exception("Cannot open HttpURLConnection"))
    }
}

 

위의 코드는 일반적인 네트워크 통신 코드이다.

 

여기서 문제는 해당 코드는 UI 스레드에서 작동한다는 점이다.

 

따라서 아래와 같은 구조로 변경해주어야 한다.

 

class LoginRepository(...) {
    ...
    suspend fun makeLoginRequest(jsonBody: String): Result<LoginResponse> {
        // Move the execution of the coroutine to the I/O dispatcher
        return withContext(Dispatchers.IO) {
            // Blocking network request code
        }
    }
}

 

 

suspend fun

  • suspend fun은 일시정지 가능한 함수라는 뜻으로 주로 비동기 함수를 사용할 때 사용된다.
  • suspend 함수를 사용하려면 같은 suspend 함수이거나, 코루틴에서 호출해야 한다.

 

withContext()

  • suspend 함수에서 사용할 수 있는 어느 스레드에서 실행할지 설정하는 메서드이다.
  • makeLoginRequest 함수는 일시정지가 가능하며, IO 스레드에서 실행되는 함수가 되었다.

 

ViewModel.kt

class LoginViewModel(private val loginRepository: LoginRepository): ViewModel() {

    fun login(username: String, token: String) {

        // Create a new coroutine on the UI thread
        viewModelScope.launch {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"

            // Make the network call and suspend execution until it finishes
            val result = loginRepository.makeLoginRequest(jsonBody)

            // Display result of the network request to the user
            when (result) {
                is Result.Success<LoginResponse> -> // Happy path
                else -> // Show error in UI
            }
        }
    }
}

 

makeLoginRequest 는 suspend 함수로 코루틴을 사용하여 호출해야하기에 코루틴을 사용한 모습이다.

또한 Dispatcher를 설정해주지 않아 UI 스레드에서 작동하도록 하여 데이터를 UI에 적용할 수 있게 만들었다.

 

요약

  • Repository Class에서 makeLoginRequest함수를 통해 IO스레드를 사용하여 네트워크 통신 결과를 리턴한다.
  • ViewModel에서 코루틴을 사용하여 UI스레드에서 makeLoginRequest함수의 결과를 받아 작업을 한다.

 

이는 절대적인 사용방법은 아니며, 응용하여 자유롭게 구현할 수 있다.

 

'안드로이드 > Asynchronous' 카테고리의 다른 글

[안드로이드] Coroutine Flow  (1) 2024.03.30
[안드로이드] 스레드  (0) 2024.03.11
[안드로이드] 동기와 비동기  (0) 2024.03.10