예외 처리에서 Lifecycle 고려하기
·
Study/Kotlin
이전 글에서 짧게 viewModelScope에서의 예외 처리 예시를 살펴보았다. 이번에는 이전 글을 바탕으로 발생할 수 있는 Lifecycle 관련 예외 처리 시나리오를 세워 본다. 문제가 될만한 상황 검토하기viewModelScope.launch { supervisorScope { val deferred = async { throw RuntimeException() } val result = try { deferred.await() } catch (e: Exception) { println(e) } // Some Ui updates(Vulnerable point) }}이 코드에서 가장 위험한 부분은 result 변수 이후에 viewModelSco..
viewModelScope 예외 처리 예시
·
Study/Kotlin
이전 글에서 coroutineScope와 supervisorScope 함수로 예외 처리하는 방법을 살펴보았다. 이제는 실전인 viewModelScope에서 어떻게 예외 처리를 하면 좋을까에 관한 내용이다. 문제 상황 살펴보기viewModelScope.launch { val deferred = async { throw RuntimeException() } val result = try { deferred.await() } catch (e: Exception) { println(e) }}이런 예시가 있다고 해보자. 내가 처음 예측했던 결과는 정상적으로 catch 문에서 예외를 잡을 수 있을 것이라 생각했다. 하지만, 결과는 앱 크래시로 이어졌다. 문제 상황 ..
supervisorScope 함수를 사용한 예외 처리
·
Study/Kotlin
이번에는 저번 글의 coroutineScope 함수와 달리 supervisorScope를 사용해보는 시간이다. 바로 예제 코드부터 보자. supervisorScope를 사용한 예외 처리 시도하기fun main() = runBlocking { try { supervisorScope { launch { throw RuntimeException() } } } catch(e: Exception) { println("Caught: $e") }}먼저 저번 글에서 coroutineScope를 supervisorScope로 대치해보았다. 실행 결과를 예측해보자. launch 내부에서 발생한 예외는 처리되지 않고 앱 크래시가 발생할 것이다. 왜..
coroutineScope 함수를 사용한 예외 처리
·
Study/Kotlin
이번 글에서는 coroutineScope라는 함수를 사용해서 예외를 처리해보도록 하겠다. 대소문자를 잘 구별해야한다. 대문자로 시작하는 CoroutineScope 함수와는 사뭇 다르다. 예외 발생 상황 보기fun main() = runBlocking { launch { throw RuntimeException() }}나는 위와 같은 코드를 실행해서 예외를 발생시킬 것이다. 당연히 launch에서 발생한 예외는 try-catch나 CoroutineExceptionHandler가 없기에비정상 종료로 이어질 것이다. try-catch로 처리해볼까?fun main() = runBlocking { try { launch { throw RuntimeException() } ..
launch vs async in Coroutines Exception Handling
·
Study/Kotlin
이번 글에서는 코루틴에서 예외를 처리할 때 launch와 async 코루틴 빌더의 차이를 살펴보려고 한다. launch 사용 예제val scope = CoroutineScope(Job())scope.launch { delay(100) throw RuntimeException()}Thread.sleep(300)이 코드를 실행하면 어떤 결과가 나올까?예외를 처리하는 부분은 없다.콘솔 창에서 볼 수 있듯 예외가 전파되어 종료되었다. async 사용 예제val scope = CoroutineScope(Job())scope.async { delay(100) throw RuntimeException()}Thread.sleep(300)이번에는 단순히 launch를 async로 바꿔보았다. 실행 결과는 과연..
Coroutines try-catch vs ExceptionHandler
·
Study/Kotlin
이번 글에서는 try-catch와 ExceptionHandler를 비교해보려고 한다. 얼핏 보기에는 둘 다 예외 처리의 기법으로만 보고 넘어갈 수도 있지만,각각 사용해야하는 상황이 다르기 때문이다. try-catch 관점try-catch는 예외가 발생하고나서도 계속 작업이 필요한 경우에 사용된다. 예를 들면, 코루틴 내부에서 재시도하는 로직이 필요한 경우이다. try-catch 구문을 사용해 예외를 잡아내고 해당 예외를 다시 전파시키지 않는다면예외는 상위 계층으로 전파되지 않는다.(부모 코루틴에게 전파되지 않는다) 예외가 발생했음에도 상위 계층으로 예외가 전파되지 않는다면Structured Concurrency를 해칠 수 있다. ExceptionHandler 관점try-catch와는 달리 계속해서 작업이..
Exception Handling Using ExceptionHandler in Coroutines
·
Study/Kotlin
이번에는 CoroutineExceptionHandler로 예외 처리를 해보도록 하자. 기존 try-catch 구문과는 어떤 차이가 있는지도 볼 예정이다. 처리할 코드val scope = CoroutineScope(Job())scope.launch { throw RuntimeException()}Thread.sleep(1000) CoroutineExceptionHandler 사용 지점이 핸들러는 Coroutine의 Context 요소이다. 이전 글에서의 기억을 떠올려본다면 가장 대표적인 Context 요소는 Dispatcher일 것이다. 또한, '+' 연산자를 사용하면 여러 Context 요소를 사용할 수 있다. 그럼 위 코드에서 어떤 위치에 핸들러를 주입해야할까? 정답은 두 위치에서 가능한데, 하나는 J..
Exception Handling Using try-catch Clause in Coroutines
·
Study/Kotlin
이번 글은 코루틴에서 try-catch절을 사용해 예외 처리를 해보는 시간이 될 것이다. 일반적인 예외 처리 상기하기fun main() { generateException()}fun generateException() { throw RuntimeException()}이런 예외를 try-catch절로 처리한 상황과 그렇지 않은 상황을 떠올려보자. 먼저 예외 처리를 해두었다면 프로그램이 정상적으로 실행이 종료된다. 그렇지 않은 경우 로그를 남기며 프로그램에 크래시가 발생한다. 코루틴에 적용해보기fun main() { val scope = CoroutineScope(Job()) scope.launch { generateException() } Thread.sleep(100)}fu..
NonCancellable Coroutines 사용해보기
·
Study/Kotlin
이전 글에서 코루틴을 취소하는 방법에 대해 설명해보았다. 여기서 생각해볼만한 것이 하나 있는데 바로 CancellationException을 사용해코루틴을 종료시키기 직전 특정 작업을 하는 경우이다. 더 정확히 따지면 suspend function 호출이 필요하지만 불가능한 경우이다. 예제 코드와 같이 보자. 예제 코드fun main() = runBlocking { val job = launch(Dispatcher.Default) { repeat(10) { index -> if (isActive) { println("repeat $index") Thread.sleep(100) } else { ..
Coroutines Cooperative Cancellation
·
Study/Kotlin
이번 글에서는 코루틴을 취소할 때 어떤 취소 방법을 취해야하는지에 대해 설명해본다. 코루틴 안에서 반복문을 실행하는 도중 취소하는 상황을 예시로 보자. 코드 예제fun main() = runBlocking { val job = launch(Dispatcher.Default) { repeat(10) { index -> println("repeat $index") Thread.sleep(100) } } delay(250) println("Cancel coroutine") job.cancel()}위 예제를 실행한 결과를 먼저 예상해보자. 만약 이 코드가 정상적으로 repeat 0~2까지만 실행됐을거라고 생각했다면 오산이다. 취소..