일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- android hilt
- Jetpack Room
- 자료구조
- 백준 2096
- 1806 투포인터
- 5582 DP
- 1003 파이썬
- 코루틴 플로우
- 6588 파이썬
- 안드로이드 hilt
- Coroutine Flow
- 1753 파이썬
- 백준 5582
- 투포인터 알고리즘
- 1644 파이썬
- 이진 탐색
- 5582 파이썬
- 2096 파이썬
- java
- git local remote
- 1806 파이썬
- 10819 파이썬
- 1806 백준
- flow buffering
- 백준 10819
- 백준 1644
- Android Room
- Android mvp
- 1753 다익스트라
- 자바
- Today
- Total
Gemstone's Devlog
Coroutine 정리 본문
https://developer.android.com/kotlin/coroutines?hl=ko
Android의 Kotlin 코루틴 | Android 개발자 | Android Developers
Android의 Kotlin 코루틴 코루틴은 비동기적으로 실행되는 코드를 간소화하기 위해 Android에서 사용할 수 있는 동시 실행 설계 패턴입니다. 코루틴은 Kotlin 버전 1.3에 추가되었으며 다른 언어에서 확
developer.android.com
우선 코루틴의 정의를 알아보기 위해 안드로이드 개발자 홈페이지에 들렸다.
코루틴에 대한 대략적인 설명이다...
이젠 기능에 대해서 알아보자.
1) 경량 : 실행 중인 스레드를 차단하지 않는 정지를 지원, 단일 스레드에서 많은 코루틴을 실행 가능. 정지는 많은 동시 작업을 지원하면서도 차단보다 메모리를 절약.
2) 메모리 누수 감소 : 구조화된 동시 실행을 사용하여 범위 내에서 작업을 실행
3) 기본으로 제공되는 취소 지원 : 실행 중인 코루틴 계층 구조를 통해 자동으로 취소가 전달
4) Jetpack 통합 : 많은 Jetpack 라이브러리에 코루틴을 완전히 지원하는 확장 프로그램이 포함되어있음.
Android 프로젝트에서 코루틴을 사용하려면 앱의 build.gradle 파일에 다음 종속 항목을 추가해야 한다.
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
}
예시를 보자.
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가 동기식이며 호출 스레드를 차단한다. 네트워크 요청의 응답을 모델링하기 위해 자체 Result 클래스를 사용한다.
ViewModel은 사용자가 예를 들어 버튼을 클릭할 때 네트워크 요청을 트리거한다.
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
loginRepository.makeLoginRequest(jsonBody)
}
}
위의 코드에서 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)
}
}
}
login 함수에서 코루틴 코드를 한 번 분석해 보자.
이 코루틴은 viewModelScope로 시작되므로 ViewModel 범위에서 실행된다.
사용자가 화면 밖으로 이동하는 것으로 인해 ViewModel이 소멸되는 경우 viewModelScope가 자동으로 취소되고 실행 중인 모든 코루틴도 취소된다.
위의 예에서 한 가지 문제는 makeLoginRequest를 호출하는 모든 항목이 명시적으로 실행을 기본 스레드 외부로 이동해야 한다는 점이다.
이 문제를 해결하기 위해 Repository를 수정하는 방법을 알아보겠다.
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
}
}
}
withContext(Dispatchers.IO) 는 코루틴 실행을 I/O 스레드로 이동하여 호출 함수를 기본 안전 함수로 만들고 필요에 따라 UI를 업데이트하도록 설정한다.
makeLoginRequest에는 suspend 키워드도 표시가 된다. 이 키워드는 코루틴 내에서 함수가 호출되도록 강제하는
코틀린의 방법이다.
다음 예에서는 LoginViewModel에 코루틴을 만드는 방법이다.
makeLoginRequest가 실행을 기본 스레드 외부로 이동하므로, 이제 login 함수의 코루틴이 기본 스레드에서 실행 될 수 있다.
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
}
}
}
}
다음은 예외처리에 대해서 알아보겠다.
Repository 레이어에서 발생할 수 있는 예외를 처리하려면 Kotlin에서 기본으로 제공되는 예외 지원을 사용해야 한다.
다음 예에서는 try-catch 블록을 사용하겠다.
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun makeLoginRequest(username: String, token: String) {
viewModelScope.launch {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
val result = try {
loginRepository.makeLoginRequest(jsonBody)
} catch(e: Exception) {
Result.Error(Exception("Network request failed"))
}
when (result) {
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI
}
}
}
}
이 예에서는 makeLoginRequest() 호출에 의해 발생한 예기치 않은 예외가 UI에서 오류로 처리가 된다...
'Kotlin (Android)' 카테고리의 다른 글
[의존성 주입] Hilt 정리 (0) | 2022.04.05 |
---|---|
[코루틴 실습] 처음 만나는 코루틴 (0) | 2022.03.30 |
코틀린 코테 테크닉 (0) | 2022.01.21 |
ViewModel과 SIS(Saved Instance State) (0) | 2022.01.17 |
지연초기화(Lazy Initialization) 자세히.. (0) | 2022.01.17 |