일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
31 |
- android DI
- 안드로이드 클린 아키텍처
- android memory leak
- 안드로이드 의존성주입
- sharedFlow
- Android App Architecture Guideline
- 안드로이드 mvvm
- 안드로이드 앱 아키텍처 가이드라인 설명
- RxJava
- 안드로이드 앱 아키텍처 가이드라인 예시
- 안드로이드 앱 아키텍처 가이드라인
- 안드로이드 JUnit
- 안드로이드 앱 아키텍처 가이드라인 사용법
- 스타트업 코딩테스트
- 안드로이드 테스트코드
- coroutine
- Hilt
- 안드로이드 Espresso
- 안드로이드 hilt
- MVVM
- 안드로이드 Mockito
- Koin
- 안드로이드 최적화
- 안드로이드 mvvm예제
- 코루틴
- 리싸이클러뷰 최적화
- android clean architecture
- 안드로이드 아키텍처 컴포넌트
- Android MVVM
- 안드로이드 리싸이클러뷰
- Today
- Total
안드로이드 연구소
안드로이드 코틀린 코루틴(coroutine) 본문
여러분들도 코루틴에 대해서 들어보셨는가요?
- 들어는 봤지만 어떤 내용인지는 모르는 사람
- 인터넷에서 예제를 복붙해서 몇 번 사용해 본 사람
- 비동기에서 처리하고 똑같은 코드로 메인쓰레드만 이용하는 사람
사실 이 사람들은 모두 똑같이 코루틴을 모르는 사람들입니다.
그 이유는 코루틴의 구성요소를 모르기 때문입니다.
- 어떤 종류의 코루틴 스코프를 사용해야하는지
- 어떤 코루틴 컨텍스트를 사용할지
- 어떤 코루틴 빌더를 호출할지
우리 개발자들은 사항에 맞게 우리는 각 각의 구성요소를 사용해줘야합니다.
다른 예제들과 달리 코루틴은 몇 번 따라해본다고 능숙하게 적용하고 응용하기가 거의 불가능합니다.
코루틴은 러닝커브(신기술을 배우고 적용하는 걸리는 시간)가 높은 편이라고 얘기하는데요.
기초 지식 없이는 다룰 수 없는 코루틴은 학문이기 때문입니다.
그렇다면 코루틴 학문에 대해서 시작해보겠습니다.
Q1. chatGPT, 코루틴에 대해서 설명해줘
코루틴은 "단일 실행 스레드" 내에서 "협동 멀티태스킹"을 허용하는 일종의 동시 프로그래밍 구조입니다.
- 기존 멀티테스킹: "여러 스레드"가 서로 다른 코어 또는 프로세서에서 동시에 실행
- 코루틴 멀티테스킹: "단일 스레드"에서 여러 작업을 동시에 실행
우선 위의 내용이 잘 이해가 되지 않지만
하나씩 살펴보면 코루틴은 일딴 멀티테스킹을 할 때는 사용되는 것 같습니다.
또 기존의 멀티테스킹과 비교해보면 여러개가 일꾼들의 움직임이 아니라
하나의 일꾼의 움직임을 보다는 느낌이 드네요.
또 예시로 파이썬 문법을 보여주고 있는데
코틀린에서만 사용하는 개념이 아닌
많은 프로그래밍 용어에서도 사용하는걸로 보입니다.
코루틴: 비동기적으로 실행되는 코드를 간소화하기 위해 Android에서 사용할 수 있는 동시 실행 설계 패턴
안드로이드에서만 사용한 개념이 아닌 1958년 어셈블리 프로그램에서부터 시작. 파이썬, 자바스크립트에서도 다 사용중.
출처: https://wooooooak.github.io/kotlin/2019/08/25/코틀린-코루틴-개념-익히기/
Q2. 안드로이드에서 사용하는 코틀린 코루틴에 대해 설명해줘.
코틀린 코루틴은 안드로이드에서 "비동기 작업"을 처리하기 위한 강력한 도구입니다.
간결하고 읽기 쉬운 비동기 작성하는 방법을 제공합니다.
코루틴을 사용하여 기본 UI 스레드를 차단하지 않고
데이터베이스 쿼리 또는 네트워크 요청같은 작업을 수행할 수 있습니다.
그렇게하여 코루틴은 앱이 강제종료되지 않고 사용자 인터페이스가 매끄럽게 동작하도록 도움을 준다.
코틀린 코루틴은 비동기 작업을 하기위한 도구로 보여집니다.
기본적으로 우리도 모르게 사용하고 있는 "UI스레드"라는 녀석을 이용하여
서버로부터 요청해가져온 데이터를 UI화면에 잘 보여줄 수 있도록 도움주고 있는 것으로 보입니다.
위 내용에 관련된 아래 예시입니다.
아래 예제에서 Dispatchers.IO를 이용해서 서버로 부터 데이터를 가져오고 있고
Dispatchers.Main을 이용해서 가져온 데이터를 화면에 출력해주고 있는 것 같습니다.
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 코루틴: 메인 쓰레드(UI쓰레드 사용)
GlobalScope.launch(Dispatchers.Main) {
// 비동기로 네트워크 호출
val result = withContext(Dispatchers.IO) {
fetchDataFromServer()
}
// UI화면 업데이트해서 출력
updateUi(result)
}
}
// 서버로부터 데이터 가져오기
private fun fetchDataFromServer(): String {
// Perform a network request
// ....
return "Data from server"
}
// UI 업데이트하여 화면 출력
private fun updateUi(result: String) {
// Update the UI with the result
textView.text = result
}
}
그렇다면 코루틴을 사용한 아래 메서드들에 대해서 한번 확인해보아야겠는데요?
GlobalScope.launch(Dispatchers.Main)
val result = withContext(Dispatchers.IO)
위의 예제에서
GlobalScope는 어떤 객체이고(코루틴 스코프)
launch와 withContext는 메서드는 어떤 역할을 하는지(코루틴 빌더)
Dispatchers.Main, Dispatchers.IO외에는 어떤것들이 있는지 알아볼까요?(코루틴 컨텍스트)
그 이전에 안드로이드에서 코루틴이 나오기 이전에는 어떻게 비동기를 다루었는지에 대한 설명은 아래 더 보기를 통해 확인해보세요.
Q. 코루틴 이전에는 안드로이드에서 비동기를 사용했어?
코루틴이 나오기 이전에는 AsyncTask를 사용하여 비동기를 처리하였습니다.
비동기가 필요한 클래스에서 AsyncTask를 상속 받은 후
doInBackground 메서드에서 네트워크로부터 데이터를 받기를 완료 후에
onPostExecute 메서드에서 기본 UI 스레드에서 호출하여 UI를 업데이트하는 데 사용할 수 있습니다.
class MyAsyncTask : AsyncTask<Void, Void, String>() {
override fun doInBackground(vararg params: Void?): String {
// Perform a long-running operation, such as a network request or database query
return "Result"
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
// Update the UI with the resul
}
}
그러나 AsyncTask는 코루틴만큼 유연하지 않고 아래와 같은 문제들로 인해 Android 11 (API level 30)Deprecated되었습니다.
- AsyncTask 실행 시 엑티비티나 프레그먼트 onDestory되면 메모리 누수 발생
- 화면 회전과 같은 configuration change때 AsyncTask파괴될 수 있음
- AsyncTask를 쉽게 취소하거나 일시 중지할 수 없으며 동시에 실행할 수 있는 작업 수를 제한할 방법이 없습니다.
- AsyncTask 실행 중에 예외가 발생하면 사용자에게 명확한 오류 메시지를 제공하지 않고 앱이 중단될 수 있습니다.
- 개발자가 백그라운드 작업 및 UI 업데이트를 처리하기 위해 상당량의 상용구 코드를 작성해야해서 복잡할 수 있습니다.
Q3. 코루틴 스코프(coroutine scope)에 대해서 알려줘.
- GlobalScope
: 최상위 코루틴 스코프.
- 다른 컨텍스트와 연결되지 않으며 독립적이다.
- 다른 코루틴 스코프들과 달리 비동기 실행 해제를 수동해줘야해서 메모리 누수가 발생할 수 있으므로 사용을 권장하지 않는다.
- 장기 실행 서버 응용 프로그램과 같이 수명 주기가 없는 응용 프로그램에 유용합니다.
- MainScope
: 안드로이드 애플리케이션의 가장 기본인 스레드인 메인스레드와 연결된 스코프.
- UI 작업을 수행해야 하는 코루틴을 시작하는 데 사용할 수 있습니다.
- Lifecycle 객체가 소멸되면 MainScope가 자동으로 취소됩니다.
- (커스텀) CoroutineScope
: Activity, Fragment, ViewModel, Service와 같은 안드로이드 구성요소에서 모두 사용가능한 커스텀 인스턴스입니다.
- 네트워크 요청이나 데이터베이스 쿼리와 같이 백그라운드에서 장기 실행 작업을하는 코루틴을 시작하는 데 사용할 수 있습니다.
- 전반적으로 적절한 수명 주기 관리를 보장하고 메모리 누수 및 기타 문제와 관련된 문제를 방지
- ViewModelScope
: viewModel내에서 데이터 로드 또는 처리시 사용하는 코루틴 스코프.
-viewModel이 destory되면 자동으로 해제된다.
-viewModel에서 그냥 커스텀 CoroutineScope를 사용하는 경우, viewModel이 소멸될 때 코루틴을 취소하지 않으면 메모리 누수 또는 기타 문제가 발생할 수 있습니다.
(코루틴이 나오기 이전의 비동기 실행인) AsyncTask에서의 문제점인 생명주기 관리 할 수 없는 문제점을
커스텀 CoroutineScope나 ViewModelScope를 이용하여 해당 문제를 해결한 것으로 보이네요.
Q4. 코루틴 컨텍스트(coroutine Context)에 대해 알려줘
: 코루틴 컨텍스트는 코루틴이 "동작하는 방식"과 "실행 위치"를 결정하는 일련의 규칙입니다.
1. Dispatcher
: 코루틴이 실행될 스레드 또는 스레드 풀을 결정하는 역할을 합니다.
- Dispatchers.Default: 지속적으로 CPU를 지속적으로 사용해야하는 무거운 작업(대규모 데이터 세트 정렬, 필터링용 스레드)
- Dispatchers.IO: 파일 읽기 또는 쓰기 + 네트워크 요청 또는 데이터베이스 작업 수행에 사용되는 스레드.
- Dispatchers.Main: 기본적으로 사용되는 일반적으로 UI 업데이트와 같은 작업용 스레드
2. Job
: 코루틴을 취소할 수 있는 작업 단위.
코루틴을 시작하면 새로운 job이 자동으로 생성되며, 필요한 경우 코루틴을 취소할 수 있습니다.
3. CoroutineExceptionHandler
: 코루틴에 의해 발생한 예외를 처리할 수 있게 해주는 역할
4. CoroutineName
: 코루틴의 이름을 나타냄. 디버깅 및 로깅 목적에 유용할 수 있습니다.
5. CoroutineScope
: 코루틴 그룹의 수명을 정의할 수 있습니다.
Dispatcher와 job이 코루틴에 실질적으로 관련된 요소로 보이네요.
잘 기억해두기.(약간의 암기는 필요합니다!)
Q5. 코루틴 빌더(coroutine builder)에 대해 설명해줘
:코루틴을 만들고 실행하는 데 사용하는 함수입니다.
1. launch
: 가장 일반적인 코루틴 빌더. 결과가 없는 코루틴을 생성하는 빌더
-코루틴을 나타내는 Job 객체를 반환합니다.
2. async
: lauch와 다르게 결과를 가지는 코루틴 생성하는 빌더
- 코루틴의 결과를 나타내는 Deferred 객체를 반환합니다.
- await 함수를 사용해 Deferred 객체의 결과를 확인할 수 있다.
3. withContext
:코루틴의 컨텍스트를 다른 디스패처로 전환(ex, 기본 백그라운드 → 메인쓰레드)하는 데 사용됩니다.
- async와 달리 await함수없이 바로 그 자리에서 결과값(T)을 반환합니다.
4. runBlocking
: 실행된 모든 코루틴들이 완료할 때까지 스레드를 점유한다.
프로그램이 종료되기 전에 모든 코루틴이 완료되었는지 확인하기 위해 사용
여기 있는 메서드들은 다 잘 쓰기 때문에 다 잘 외우기
Q6. 가장 대표적인 코루틴 예시를 보여줘.
아래 예시는 네트워크로 통신한 데이터로 UI업데이트를 해주는 동작을 한 작업입니다.
기본적으로 네트워크 통신을 하기위해 CoroutineScope를 사용하였고
(CoroutineScope가 초기화될 때 생성되는 Job 개체는 명시적으로 반환되지 않습니다.)
CoroutinScope.launch를 이용하여 Dispatchers.IO에서 네트워크로 불러온 데이터를 가져왔습니다.
그 후 withContext로 Dispatcher.Main에서 UI를 업데이트 해주었습니다.
그리고 마지막으로 CoroutineScope의 메모리 누수를 막기 위해 처음에 생성해준 job객체를 종료하였습니다.
class MyActivity : AppCompatActivity() {
// Create a Job for the coroutine scope
private val job = Job()
// Create a new coroutine scope(메인스레드로 설정)
private val coroutineScope = CoroutineScope(Dispatchers.Main + job)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my)
// Dispatchers.IO 코루틴 백그라운드 실행하여 네트워크 통신
coroutineScope.launch(Dispatchers.IO) {
val result = makeNetworkRequest() // 요청한 데이터
// Dispatchers.Main으로 스레드 변경하여 UI업데이트
withContext(Dispatchers.Main) {
// UI Update...
}
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // 액티비티 파괴 시 스레드 취소 => 메모리 누수 예방
}
// 네트워크 통신으로 데이터 요청
private suspend fun makeNetworkRequest(): String {
// Make a network request and return the result
}
}
CoroutinScope로 코루틴의 생명주기를 쉽게 관리해주고
lauch로 새로운 스레드를 불러오고 withContext로 새로운 스레드를 변환해주었습니다.
이제 코루틴의 하나하나가 보이시나요?
'안드로이드 연구소 > 비동기' 카테고리의 다른 글
Flow 심화2: EventFlow (1) | 2023.11.13 |
---|---|
Flow 심화1: StateFlow와 SharedFlow (2) | 2023.11.12 |
[Flow vs RxJava] Flow(Coroutine Flow) (0) | 2023.06.07 |