안드로이드 프로그래밍을 하다보면 Couroutine(코루틴)이라는 용어를 들어보셨을 것입니다. 코투린이란 코 = co(함께, 동시에)라는 의미를 가지고 있습니다. 즉, 동시성 프로그래밍 개념을 코틀린에 도입한 것이 코투린 이라고 합니다.
코루틴은 코루틴이 시작된 스레드를 중단하지 않으면서 비동기적으로 실행되는 코드입니다.
즉, 코루틴이란 함께 동작하면서 규칙이 있는 일의 순서를 의미합니다.
기존의 복잡한 AsyncTask는 API 30부터 Deprecated되었으며 대신에 Coroutine을 권장합니다.
결국 코루틴은 실행이 마지막으로 중단되었던 지점의 바로 다음장소에서 실행을 재개한다고 볼 수 있습니다.
보통 일반적인 함수는 중단되는 개념엇이 어떤 루틴이 있으면 해당 루틴을 끝까지 실행한 후 종료되고 빠져나오는 방식이라면 코루틴은 진입하는 입구과 나오는 출구점이 여러개 입니다.
-> 코투린이 메인스레드가 blocking되는 부분에 대해서도 도움을 주고, 비동기 처리코드를 순차적인 코드로 만들 수 있게 해줍니다.
비동기, 비동기라는 말은 코루틴을 공부하다보면 계속해서 나오는 단어이다. 그렇기에 비동기라는 개념에 대해서 정확하게 이해하지 못한다면 Coroutine을 정확하게 이해할 수 없기에 본격적으로 코루틴에 들어가기전 비동기에 대해서 먼저 설명하겠습니다.
비동기의 개념을 설명하기 보다는 예시로 설명하겠습니다.
어떤 일을 처리할 때 하나의 작업만을 할 수 있다면 동기입니다. "돈을 계산한다, 숫자를 센다, 노래를 부른다"와 같은 것은 하나의 작업만을 하고 있기 때문에 동기입니다.
반면 비동기란 "티비를 보면서 돈을 계산한다." 이렇게 여러개의 작업을 동시에하는 것을 비동기라고 합니다.
코드에서는 처리해야하는 시간이 오래 걸리는 작업들이 있습니다.
네트워크를 통한 작업
DB에 데이터 수정 및 삭제
와 같이 코트내에서만이 아닌 외부의 어떠한 환경과 결합하여 하는 작업의 경우 내부에서 처리하는 것보다 시간이 오래걸립니다.
만약 위의 같은 작업들을 동기로 처리하게 된다면
그 작업뒤에 있는 작업들은 위의 작업이 끝나기를 기다려야한다. 그 뜻은 사용자또한 그 시간동안 앱을 키고 가만히 있어야한다는 뜻입니다. 이러한 문제들을 없애기 위해 코루틴을 통해 이러한 작업들은 Main 스레드가 아닌 별개의 스레드에서 무거운 작업들을 처리해야하는 것입니다.
Main : 메인 스레드, 화면 ui 작업 등을 하는 곳
IO : 네트워크, DB 등 백그라운드에서 필요한 작업을 하는 곳
Default : 정렬이나 무거운 계산 작업 등을 하는 곳
launch : 동기
async : 비동기
CoroutineScope(Dispatchers.IO).async{
}
다음과 같은 코드는?
네트워크 작업을 하는 스레드를 비동기로 작업한다는 의미입니다.
또한 어떠한 작업에서 await라는 명령어가 붙어져있을 수 있습니다. 이 뜻은 작업이 완료될 때 까지 기다리겠다는 것입니다.
이러한 명령어는 비동기식으로 작업을 한 결과를 어딘가에 넣어 사용자에게 보여줘야하는 경우에서 사용을 합니다.
CoroutineScope(Dispatchers.Main).launch{
val http = CoroutineScope(Dispatchers.Default).async {
gethttp()
}.await()
Toast.makeText(this,"작업1",Toast.LENGH_SHORT).show()
}
Toast.makeText(this,"작업2",Toast.LENGH_SHORT).show()
위의 코드에서 어떠한 Toast메시지가 먼저 출력일 될까?
정답은 작업 2입니다.
gethttp()라는 작업을 별개의 스레드에서 작업을 끝낼 동안 Main쓰레드에서는 다음 작업을 쭉 진행하는 것입니다.
그렇기에 작업2가 먼저 출력이 되는데 이게 바로 코루틴을 이용한 비동기 실행 개념인 것입니다.
어떠한 작업을 통해 새로운 결과를 ui에 보여줘야하는 경우가 발생합니다. 이러한 경우에 Handler를 이용해 postDelayed를 통해 delay를 해줄 수 있지만 이러한 기능은 정해진 시간만큼만 기다리다가 넘어가버린다는 것입니다. 이러면 다음과 같은 문제점이 발생할 수 있습니다.
예상 보다 어떠한 작업이 빨리 끝나는 경우 -> 이러한 경우에는 작업이 이미 끝났음에도 지정한 시간이 지나기를 사용자는 대기해야한다는 것입니다.
예상 보다 어떠한 작업이 더 늦어지는 경우 -> 작업이 덜 끝났음에도 지정한 시간이 지났기에 다음 동작을 수행해버려 사용자에게 원하는 결과를 보여주지 못할 수 있습니다.
위의 같은 문제들을 Handler 대신에 Coroutine을 통해 해결하는 것입니다.
CoroutineScope(Dispatchers.Main).launch{
val http = CoroutineScope(Dispatchers.Default).async{
gethttp()
}.await
resultshow()
}
이러한 예시코드 방법으로 작성을 하게된다면 resultshow()함수는 gethttp()라는 메서드가 종료된 이후에 동작을 하게 됨으로 위의 2가지의 경우를 배제할 수 있게됩니다.