아직 Java에는 없지만 Kotlin에는 있는 내용
thread 하나당 여러 개의 작업을 하는것
화구(CPU)가 하나에 한 요리만 할 수 있기 때문에 한 요리만 하는 요리사(thread)가 번갈아가면서 사용하는 상황이라면, Coroutine은 요리사(thread) 하나가 요리를 여러 개 가지고 있다가 화구에 번갈아가면서 사용하는 느낌
Coroutine [코루틴] - 경량스레드 : 스레드를 멈추지 않고 비동기처리, 하나의 스레드 안에 여러 개의 코루틴 실행
스레드가 요리사라면 멀티 스레드는 여러 요리사가 화구(cpu)를 번갈아 사용하는 구조 - 다른 요리사가 사용중에 기존 요리사는 동작을 멈춤
코루틴은 하나의 요리사(스레드)가 파스타를 만들면서 스테이크를 굽는 형식 - 팬이 2개, 자리를 비켜가면서 멈추는 행동이 없어 좀 더 빠르게 동시 작업 가능
코루틴을 구동하는 2개의 범위(Scope)가 존재함
1. GlobalScope : 앱 전체의 생명주기와 함께 관리되는 범위
2. CoroutineScope : 버튼 클릭과 같은 특정 이벤트 순간에 해야할 Job을 위해 실행되는 범위 [ ex. network 통신, DB CRUD, 특정연산수행 등 ]
무슨 작업을 누가할지는 job scheduler가 알아서 관리해줌
실행명령은 launch
와 async
가 있음
오직 MainThread만 UI작업 가능!!
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
그렇다면 모든 작업을 MainThread에게 시키면 되느나..?
MainThread는 네트워크 작업 불가능!!
NetworkOnMainThreadException
당근마켓처럼 내위치를 가져와서 그 위치 정보를 기반으로 정보를 가져와야하는 경우가 생김
이때, 동기맞추는 작업이 중요!!!
launch를 이용하여 여러 작업 걸어놓을 수 있음
binding.btn6.setOnClickListener {
CoroutineScope(Dispatchers.Default).launch {
//작업1
launch {
for(n1 in 1000..1010) Log.d("TAG", "$n1")
delay(500)
}
//작업2
launch {
for(n2 in 2000..2010) Log.d("TAG", "$n2")
delay(500)
}
}
}
join()
: 작업이 끝날때가지 다른 코루틴은 대기, 여러 개의 작업을 순차적으로 수행하도록 할 수 있음
binding.btn7.setOnClickListener {
CoroutineScope(Dispatchers.Default).launch {
//작업1
launch {
for(n1 in 1000..1010) Log.d("TAG", "$n1")
delay(500)
}.join() //작업1이 끝날때까지 다른 코루틴은 대기
//작업2
launch {
for(n2 in 2000..2010) Log.d("TAG", "$n2")
delay(500)
}
}
}
suspend
: 코루틴 스코프 범위 밖에서 코루틴의 기능을 사용할때 suspend 함수로 만들면 사용가능
suspend fun someTask(){
for(n in 1000..1010){
Log.i("TAG","someTask : $n")
delay(500) //메소드 내에서 코루틴 기능을 사용할 수 없음
}
}
CoroutineScope 참조 가능
Job 타입으로 참조하여 cancel()
로 task 종료
var job:Job ?= null
binding.btn9.setOnClickListener {
job = CoroutineScope(Dispatchers.Default).launch {
for(n in 300..310){
Log.d("TAG", "n : $n")
delay(500)
}
}
}
binding.btn10.setOnClickListener {
job?.cancel()
}
코틀린 언어에서 지원하는 Coroutine은 두 종류 : GlobalScope, CoroutineScope
안드로이드는 액티비티 or 프래그먼트의 라이프사이클이 존재, 이에 함께 반응하는 코루틴이 있음
LifecycleScope / ViewModelScope - 별도의 라이브러리
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
lifecycleScope
안드로이드의 라이프사이클에 같이 제어되는 코루틴 스코프
사용하는 액티비티 혹은 프래그먼트의 라이프사이클에 맞춰지므로(onCreate()
~ onDestroy()
까지의 액티비티 라이프사이클 Owner) this.lifecycleScope
로 사용하는 것이 맞지만, this는 생략
private fun clickBtn(){
lifecycleScope.launch {
for (n in 0..20) {
Log.d("TAG", "lifecycle scope : $n")
delay(500)
}
}
}
언어에서의 Coroutine은 라이프사이클과 상관없이 앱이 꺼져도 끝까지 작업하지만, 안드로이드의 Coroutine은 액티비티나 프래그먼트가 destroy()되면 작업을 멈춤
launchWhenResumed
: onResume ~ onPause()일 동안에만 코루틴 동작, onPause()되면 자동 일시정지, onResume()이면 알아서 다시 실행
fun clickBtn(){
lifecycleScope.launchWhenResumed {
loopTask()
}
}
suspend fun loopTask(){
for(n in 300..320){
Log.d("TAG", "lifecycle scope when resume : $n")
delay(500)
}
}