본문 바로가기

[Android]/Coroutines

[Coroutines 마스터] Coroutine Cancellation 상세 처리

안녕하세요!

 

허접 샴푸입니다.

 

오늘은 Coroutine Cancellation 처리에 대해서 자세하게 다루어 볼까 합니다.

 

[문제점]

전 포스트에서, job.cancel()을 통해 실행 중인 Coroutine을 취소하였는 데 취소된 상태로 화면이 남아있었습니다.

취소가 되었다면 다시 실행이 가능토록 해야 하는 데 말이죠.

그렇다고 job.cancel() 이후에 onStop() 오버라이드 함수 내에서 Button을 다시 Enabled 하고, TextView를 다시 세팅한다는 것이 

가독성도 떨어지고 유지보수에도 매우 힘들 것으로 판단됩니다.

그럼 어떻게 처리해야 할까요? 방법은 다양하겠지만 제가 생각하는 좋은 방법을 말씀드리도록 하겠습니다.

 

[개요]

Coroutine의 경우 실행 중인 Coroutine이 취소되었을 경우, CancellationException을 발생시킵니다.

따라서 실행 중인 Coroutine을 취소하게 될 경우 CancellationException을 Catch 하여 코드를 완성도 있게 작성할 수 있습니다.

 

[예제]

(설명) 23번째 줄부터 37번째 줄 까지, try catch 블록 코드로 CancellationException을 catch 합니다.

53번째 줄에서 job?.cancel()을 실행시키면, 31번째 줄의 CancellationException 블록으로 빠지게 됩니다.

이때 tvMessage.text = "Cancelled"를 통해서 화면에 "Cancelled" 문구를 출력합니다.

더불어 try catch 블록의 경우 무슨 일이 있어도, finally 블록이 마지막에 호출되기 때문에, finally 블록 내에서 Disabled 되었던 Button을 다시 Enabled 시켜주고, tvTime.text=""로 초기화해줍니다.

 

[실행화면]

1. Button을 클릭하면 tvMessage(상태 TextView)에 "Started"가 출력되고, tvTime(타임 기록 TextView)에 시간이 남은 시간이 출력됩니다.

2. (동그라미) 홈 버튼을 클릭하여 바탕화면으로 화면이 전환될 경우, 위 코드의 onStop 오버라이드 함수가 호출되며, job?.cancel()이 호출되어 실행 중인 Coroutine이 작동을 멈추게 됩니다.

3. 다시 앱으로 돌아올 경우, tvMessage에 "Cancelled" 문구가 출력됨을 확인할 수 있습니다. 이는 try catch 문에서 CancellationException을 정확히 catch 하여 tvMessage.text = "Cancelled"가 실행됨을 알 수 있습니다.

4. 더불어 finally 블록 코드 또한 타기에, Button이 다시 Enabled 되었으며, tvTime.text = "" 를 통해 남은 시간은 비어있는 문자열로 화면에 보이게 됩니다.

5. 나머지는 단순 실행화면이며 참고하시기 바랍니다.

 

[결론]

- 즉, Coroutine을 취소 하기 위해 job?.cancel()를 실행하면, 동작중인 job의 Coroutine은 CancellationException을 throw 하기에, try catch 문을 작성하고 CancellationException을 catch 하는 블록에서 Cancel 관련 처리를 하시면 됩니다. 

- Cancel을 하면 CancellationException을 catch 하게 되며 이것만 알아두면 됩니다! (Cancel <-> CancellationException)

 

[Github] 코드를 받아보세요.

https://github.com/DJDrama/Coroutines/tree/Cancellation-Exception-Handling

 

GitHub - DJDrama/Coroutines

Contribute to DJDrama/Coroutines development by creating an account on GitHub.

github.com

 

 

실행 중인 Coroutine을 취소할 때 job.cancel() 말고도 해당 scope.cancel() 혹은 scope.coroutineContext.cancel() 혹은 scope.coroutineContext.cancelChildren() 등이 있는 데 이 부분에 대해선 다음 포스트에서 알아보도록 하겠습니다.

 

좋아요 구독 눌러주시면 매우 감사하겠습니다.