먼저 Coroutine이 작동하는 Thread를 변경하는 것에 대해서 다루겠습니다.
문제 상황
이전 Hello Couroutine! 에서는 코루틴을 사용해 백그라운드 스레드에서 로그를 남기도록 했습니다.
하지만 UI를 수정하는 작업을 백그라운드 스레드에서는 할 수 없어 UI 관련 작업은 할 수 없었습니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnDownloadUserData.setOnClickListener {
// 버튼 클릭시 백그라운드 스레드에서 코루틴 실행함
CoroutineScope(Dispatchers.IO).launch {
downloadUserData()
}
}
}
private fun downloadUserData() {
// 현재 스레드 이름 로그로 남기도록 함
Log.i("MyTag", "Hello Coroutine! in ${Thread.currentThread().name}")
}
}
해결책
이번에는 Coroutine Suspending 함수인 withContext()와 delay()를 통해 백그라운드 스레드에서 메인 스레드로 변경해 UI 관련 작업을 해보도록 하겠습니다.
withContext()를 사용할 때 코루틴 컨텍스트를 Dispatchers.Main으로 지정함으로써 메인 스레드에서 작업할 수 있도록 할 수 있습니다.
withContext()에 대한 자세한 설명은 해당 문서에 있습니다.
class MainActivity : AppCompatActivity() {
private var count = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnDownloadUserData.setOnClickListener {
// 버튼 클릭시 백그라운드 스레드에서 코루틴 실행함
CoroutineScope(Dispatchers.Main).launch {
downloadUserData()
}
}
}
private suspend fun downloadUserData() {
withContext(Dispatchers.Main) {
for (i in 1..200000) {
// 현재 스레드 이름과 텍스트 뷰에 보이도록 함
tvUserMessage.text = "Hello Coroutine! $i in ${Thread.currentThread().name}"
delay(1)
}
}
}
}
결과
버튼 클릭시 TextView에 메인 스레드 이름과 번호가 변경되는 것을 확인할 수 있습니다.
Suspending Functions (중단 함수)
coroutine이 suspended 될 때 실행된 함수의 현재 stack frame은 복사되고 메모리에 저장됩니다.
tasks를 완수하고 함수가 resume되면 stack frame은 저장된 곳에서 가져오고 다시 시작합니다.
코틀린 코루틴 API의 suspending functions에는 다음과 같은 것이 있다.
- withContext
- withTimeout
- withTimeoutOrNull
- join
- delay
- await
- supervisorScope
- coroutineScope
Retrofit 또는 Room같은 라이브러리도 suspending 함수를 제공합니다.
suspending 함수를 사용한다면 호출 함수에 suspend를 표시해줘야 합니다.
private suspend fun downloadUserData() {
withContext(Dispatchers.Main) {
for (i in 1..200000) {
// 현재 스레드 이름과 텍스트 뷰에 보이도록 함
tvUserMessage.text = "Hello Coroutine! $i in ${Thread.currentThread().name}"
delay(1)
}
}
}
suspend modifier가 있는 suspend 함수는 코루틴 block에서만 호출이 가능합니다.
// 버튼 클릭시 백그라운드 스레드에서 코루틴 실행함
CoroutineScope(Dispatchers.Main).launch {
downloadUserData()
}
또는 다른 suspending 함수에서만 호출이 가능합니다.
평범한 함수에서는 suspending 함수를 호출할 수 없습니다.
참고 : kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
'Language > Kotlin' 카테고리의 다른 글
코틀린[Kotlin] 기본 문법 2 (클래스, 제너릭, 상속) (0) | 2021.09.22 |
---|---|
코틀린[Kotlin] 기본 문법 1 (함수, 변수, 널 안전성) (0) | 2021.09.22 |
Coroutine을 사용한 동시성 프로그래밍과 async, await (0) | 2021.02.17 |
Kotlin Coroutine Scope, Context, Dispacher에 대해서 (0) | 2021.02.17 |
Kotlin Coroutine 소개 및 Hello Coroutine! (0) | 2021.02.17 |