Coroutine

채현·2023년 6월 5일
0

안드로이드

목록 보기
29/37

아직 Java에는 없지만 Kotlin에는 있는 내용

thread 하나당 여러 개의 작업을 하는것
화구(CPU)가 하나에 한 요리만 할 수 있기 때문에 한 요리만 하는 요리사(thread)가 번갈아가면서 사용하는 상황이라면, Coroutine은 요리사(thread) 하나가 요리를 여러 개 가지고 있다가 화구에 번갈아가면서 사용하는 느낌

Coroutine [코루틴] - 경량스레드 : 스레드를 멈추지 않고 비동기처리, 하나의 스레드 안에 여러 개의 코루틴 실행

스레드가 요리사라면 멀티 스레드는 여러 요리사가 화구(cpu)를 번갈아 사용하는 구조 - 다른 요리사가 사용중에 기존 요리사는 동작을 멈춤
코루틴은 하나의 요리사(스레드)가 파스타를 만들면서 스테이크를 굽는 형식 - 팬이 2개, 자리를 비켜가면서 멈추는 행동이 없어 좀 더 빠르게 동시 작업 가능

코루틴을 구동하는 2개의 범위(Scope)가 존재함
1. GlobalScope : 앱 전체의 생명주기와 함께 관리되는 범위
2. CoroutineScope : 버튼 클릭과 같은 특정 이벤트 순간에 해야할 Job을 위해 실행되는 범위 [ ex. network 통신, DB CRUD, 특정연산수행 등 ]

무슨 작업을 누가할지는 job scheduler가 알아서 관리해줌

실행명령은 launchasync가 있음

코루틴의 종류

오직 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)
        }
    }

0개의 댓글