최근 업무 도중, runBlocking 을 사용한 적이 있어 회고하고자 글을 작성한다.
runBlocking 을 사용하면서 Coroutine 을 사용하게 되면, Coroutine 이 종료될 때까지 스레드를 정지시키며 끝날 때까지 대기하게 된다. 이런 이유로.. 무조건 가급적 최대한 runBlocking 을 사용하지 말아야 한다는 선입견과 편견으로 가득차 있었다.
Android 에서 runBlocking 을 main thread 에서 실행하게 되면 어떻게 될까? 당연하게도 해당 Coroutine 이 종료되기 전까지 Main Thread 를 정지시키게 되므로 runBlocking Scope 내부 로직의 처리가 오래 걸린다면 ANR 이 발생할 수도 있고, 화면이 버벅거리는 것과 같은 현상이 발생할 수도 있다. 최소한 여기에서 알 수 있는 점은 Main Thread 에서는 사용하지 말아야 한다는 것이다.
현재 맡은 프로젝트에서 캘린더 데이터를 서버에 저장되어 있는 캘린더 데이터와 상호 연동하는 기능이 있는데, Android 에서 이 기능을 구현하기 위한 동기화 어댑터를 수정해야 할 일이 생겼다. AbstractThreadedSyncAdapter 를 상속받아 구현한 어댑터인데, 그 중 onPerformSync
메서드는 백그라운드 스레드에서 동작한다. 기존 코드 상에서는 Coroutine Scope 이 존재하지 않았고, Coroutine Scope 을 onPerformSync
메서드 중간부 ~ 끝까지 감싸도록 로직을 수정했다. 그런데 로직을 수정하고 난 뒤, 1번 호출되어야 할 onPerformSync
메서드가 여러 번 호출되기 시작했다.
그 이유를 알고 보니, onPerformSync
의 중간부 ~ 마지막 로직까지 Coroutine Scope 으로 감싸게 되면서 메서드는 종료되었으나 Coroutine 은 종료되지 않았기 때문에 발생한 현상으로 보였다. 그래서 Coroutine 이 종료될 때까지 기다릴 수 있도록 runBlocking 을 사용했고, 중복 호출되던 onPerformSync
메서드는 정상적으로 1번 호출되었다.
처음에는 별 생각 없이, runBlocking 을 사용하는 것은 좋지 않다! 라는 생각을 했다. Coroutine 을 중단시키는 suspend 메서드와는 달리 스레드를 중단시켜 버리니까.
그런데 곰곰히 생각해 보니, onPerformSync
메서드는 Main Thread 에서 동작하는 것이 아니라 백그라운드 Thread 에서 동작하며 데이터 동기화를 구현하는 코드이기 때문에, runBlocking 을 사용하게 되었다.
Kotlin Coroutines 의 runBlocking은 언제 써야 할까? 잘 알고 활용하자!
Android Developer - Content Provider