[Android Docs] Kotlin Coroutines on Android(1)

박주호·2022년 4월 18일
0

Kotlin coroutines on Android

원본 문서

내용 정리

  • 코루틴은 비동기적으로 실행되는 코드르 간소화하기 위해 사용하는 실행 설계 패턴이다.
  • 실행중인 스레드를 차단하지 않고 정지하므로 단일 스레드에서 많은 코루틴을 사용할 수 있다.
  • 메모리 누수가 감소한다.
  • 실행중인 코루틴은 계층 구조를 통해 자동으로 취소된다.
  • 잭팩 라이브러리가 지원된다.

Interpretation

Kotlin coroutines on Android

A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages.

코루틴은 비동기적으로 실행되는 코드를 간소화하기 위해 안드로이드에서 사용하는 병행 디자인 패턴이다. 코루틴은 코틀린 버전 1.3에서 추가되었고 다른 언어에서 확립된 개념을 기반으로 한다.

On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive. Over 50% of professional developers who use coroutines have reported seeing increased productivity. This topic describes how you can use Kotlin coroutines to address these problems, enabling you to write cleaner and more concise app code.

안드로이드에서 코루틴은 메인스레드가 차단되거나 앱에서 미반응을 야기할 수 있는 장기 실행 작업을 관리하는데 도움을 준다. 코루틴을 사용하는 전문가들의 절반 이상은 생산성이 증가했다고 보고했다. 이 주제에서는 어떻게 간결하고 깔끔한 코드가 사용하면서 이러한 문제를 해결하기위한 코루틴을 사용하는 방법을 설명한다.

Features

Coroutines is our recommended solution for asynchronous programming on Android. Noteworthy features include the following:

코루틴은 비동기 프로그래밍에 권장되는 솔루션이다. 주목할만한 특징은 다음과 같다.

  • Lightweight: You can run many coroutines on a single thread due to support for suspension, which doesn't block the thread where the coroutine is running. Suspending saves memory over blocking while supporting many concurrent operations.

경량: 코루틴이 실행할 때 스레드를 차단하지않고 중지를 지원하기때문에 단일 스레드에서 많은 코루틴을 실행할 수 있다. 중지는 수 많은 병행 작업을 하는 동안 차단보다 메모리를 절약한다.

  • Fewer memory leaks: Use structured concurrency to run operations within a scope.

적은 메모리 낭비 : 구조화된 병행성을 사용해서 범위 내에서 연산한다.

  • Built-in cancellation support: Cancellation is propagated automatically through the running coroutine hierarchy.

기본으로 제공되는 취소 : 취소는 코루틴 계층을 통해 자동으로 전달된다.

  • Jetpack integration: Many Jetpack libraries include extensions that provide full coroutines support. Some libraries also provide their own coroutine scope that you can use for structured concurrency.

잭팩 통합 : 많은 잭팩 라이브러리를 지원한다. 몇몇 라이브러리도 병행 구조로 코루틴 범위에서 사용할 수 있다.

Examples overview

Based on the Guide to app architecture, the examples in this topic make a network request and return the result to the main thread, where the app can then display the result to the user.

앱 아키텍처 가이드를 기반으로 이 주제의 예제는 메인 스레드에서 네트워크 요청과 반환을 한다. 그리고 앱은 유저에게 결과를 표시할 수 있다.

Specifically, the ViewModel Architecture component calls the repository layer on the main thread to trigger the network request. This guide iterates through various solutions that use coroutines keep the main thread unblocked.

특히 뷰모델 아키텍처 컴포넌트는 메인스레드에서 트리거 하기위해 저장소 레이아웃을 호출한다. 이 가이드에서는 차단되지 않은 메인스레드를 유지하며 코루틴을 사용하는 다양한 해결책을 반복한다.

ViewModel includes a set of KTX extensions that work directly with coroutines. These extension are lifecycle-viewmodel-ktx library and are used in this guide.

뷰모델은 코루틴과 직접 작업하는 ktx를 포함한다. 이런 확장은 lvk 라이브러리이며 가이드에서 사용된다.

Executing in a background thread

Making a network request on the main thread causes it to wait, or block, until it receives a response. Since the thread is blocked, the OS isn't able to call onDraw(), which causes your app to freeze and potentially leads to an Application Not Responding (ANR) dialog. For a better user experience, let's run this operation on a background thread.

메인스레드에서 네트워크요청 생성은 응답을 받을 때까지 대기하거나 차단된다. 스레드가 차단된 이후 운영체제는 onDraw 메소드를 호출할 수 없으므로 앱의 중지를 야기시키고 궁극적으로 ANR 다이얼로그를 불러올 수 있다. 더 나은 사용자 환경을 위해 백그라운드 스레드에서 작업을 실행해보자.

First, let's take a look at our Repository class and see how it's making the network request:

첫째로 Repository 클래스와 어떻게 네트워크 요청을 하는지 보자.

sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
}

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"))
    }
}

makeLoginRequest is synchronous and blocks the calling thread. To model the response of the network request, we have our own Result class.
The ViewModel triggers the network request when the user clicks, for example, on a button:

makeLoginRequest은 동기식이며 호출하는 스레드를 차단한다. 네트워크요청의 응답에 모델링 하기 위해 Result 클래스를 사용한다. 뷰모델은 사용자의 클릭(ex.버튼)의 네트워크 요청을 트리거합니다.

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {
    fun login(username: String, token: String) {
        val jsonBody = "{ username: \"$username\", token: \"$token\"}"
        loginRepository.makeLoginRequest(jsonBody)
    }

}

With the previous code, LoginViewModel is blocking the UI thread when making the network request. The simplest solution to move the execution off the main thread is to create a new coroutine and execute the network request on an I/O thread:

앞선 코드에서 LoginViewModel은 네트워크 요청시 UI스레드를 차단한다. 메인스레드 외부로 실행을 옮기는 가장 간단한 해결 방법은 새로운 코루틴을 만들고 I/O 스레드에서 네트워크 요청을 실행하는 것이다.

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

    fun login(username: String, token: String) {
        // Create a new coroutine to move the execution off the UI thread
        viewModelScope.launch(Dispatchers.IO) {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"
            loginRepository.makeLoginRequest(jsonBody)
        }
    }
}

Let's dissect the coroutines code in the login function:

  • viewModelScope is a predefined CoroutineScope that is included with the ViewModel KTX extensions. Note that all coroutines must run in a scope. A CoroutineScope manages one or more related coroutines.

뷰모델 스코프는 ktx에 포함된 사전 정의된 코루틴 스코프이다. 모든 코루틴은 범위내에서 실행되어야한다. 코루틴 스코프는 하나 이상의 코루틴을 관리한다.

  • launch is a function that creates a coroutine and dispatches the execution of its function body to the corresponding dispatcher.

런처는 코루틴을 만들고 그 메소드를 실행하는 디스패처이다.

-Dispatchers.IO indicates that this coroutine should be executed on a thread reserved for I/O operations.

IO디스패처는 코루틴을 I/O 작업을 예약된 스레드에서 실행해야함을 나타낸다.

The login function is executed as follows:

  • The app calls the login function from the View layer on the main thread.

앱은 메인스레드에서 뷰레이아웃으로부터 로그인 메소드를 호출한다.

  • launch creates a new coroutine, and the network request is made independently on a thread reserved for I/O operations.

런처는 새로운 코루틴을 생성하고 네트워크 요청은 I/O 작업에 대한 예약된 스레드에서 독립적으로 네트워크 요청이 이루어 진다.

  • While the coroutine is running, the login function continues execution and returns, possibly before the network request is finished. Note that for simplicity, the network response is ignored for now.

코루틴이 실행하는 동안 로그인 메소드는 가능한 네트워크 요청이 끝나기전까지 실행과 리턴이 지속된다. 편의를 위해 현재 네트워크 요청은 무시된다.

Since this coroutine is started with viewModelScope, it is executed in the scope of the ViewModel. If the ViewModel is destroyed because the user is navigating away from the screen, viewModelScope is automatically cancelled, and all running coroutines are canceled as well.

이 코루틴은 viewModelScope로 시작되므로 뷰모델 범위에서 실행된다. 만약 뮤모델이 사용자가 화면을 벗어나 파괴된다면 뷰모델스코프는 자동으로 취소되고 실행되고있는 모든 코루틴은 마찬가지로 취소된다.

One issue with the previous example is that anything calling makeLoginRequest needs to remember to explicitly move the execution off the main thread. Let's see how we can modify the Repository to solve this problem for us.

위 예제에서 한가지 문제는 makeLoginRequest 메소드를 요청하는 경우 명시적으로 실행을 매인스레드 외부로 이동해야 한다. 이제 이런 문제를 해결하기 위해 수정하는 방법을 알아보자.


📗 단어 정리 📘

영어한글
concurrency병행성
concise간결한
Noteworthy features주목할만한 특징
propagate전달하다
dissect분석하다
Note that for simplicity편의를 위해
explicitly명시적으로
profile
항상 배우려는 자세로

0개의 댓글