Intermediate operator 알아보기
·
Study/Kotlin
이번에는 우리가 Flow를 통해 특정 리스트를 업데이트할 때,초기 로딩 상태를 보여주길 원한다는 가정을 해보자. 심지어 이 리스트가 네트워크 작업으로 인해 얼마나 지연될지 모르기 때문에언제 업데이트가 끝날지 모른다면 더욱이 로딩 중이라는 표시를 해주는 것이 마땅하다. 이를 구현하기 전에 Intermediate operator를 먼저 알아보려 한다. Onstart이 함수로는 collect가 시작될 때 실행되는 동작을 정의할 수 있다. 함수로 정의한 동작의 실행은 다시 강조하면 첫번째값이 방출될 때가 아닌 collect가 시작될 때이다. OnCompletion이 함수는 Flow가 완료된 후 실행되는 동작을 정의할 수 있다. 여기서 Flow가 완료되는 방식은 두가지가 있다.모든 값이 정상적으로 방출된 경우예외..
launchIn 살펴보기
·
Study/Kotlin
이번에는 저번에 작성했던 기본적인 Terminal operator에 이어 launchIn을 소개해보려 한다. launchIn 문서보기이 함수는 정의부터 조금 특이하다. 다른 Terminal operator는 모두 suspend 함수였는데 이 함수는 일반 함수이다. 그리고 CoroutineScope를 전달하면 내부적으로 launch와 collect까지 실행한다는 사실을 볼 수 있다. 소스 코드를 확인해보면 실제로 그렇게 생겼다. 그렇다면 코드로 어떻게 실행하는 지 확인해보자. 예제 살펴보기fun main() { val flow = flow { println("Emit first value") emit(1) delay(100) prin..
Flow의 기본적인 최종 연산자 알아보기(Terminal operator)
·
Study/Kotlin
이전 글에서는 단순히 Flow를 만들어보았다. 이제 Flow에서 방출하는 값을 어떻게 가져올 수 있는지 그 방법에 대해 살펴보자. Flow 만들어보기다짜고짜 Flow를 만들어본다는 게 무슨 의미일까? fun main() { val flow = flow { println("Emit first value") emit(1) delay(100) println("Emit second value") emit(2) }}이렇게 Flow를 만들면 과연 나는 이 print문을 콘솔에서 확인할 수 있을까? 정답은 '아니다'이다. 간단히 생각해봤을때 이미 delay, emit 함수는 suspend function으로 코루틴 내부에서 실행되어..
Flow 만들어보기(feat. Flow builder)
·
Study/Kotlin
이번 글에서는 Flow builder를 사용해 Flow를 만들어본다. flowOf 사용하기첫번째는 flowOf라는 함수를 사용해 Flow를 생성해보겠다. val flow1 = flowOf()val flow2 = flowOf(1, 2, 3)흔히 MutableList를 만드는 방식과 매우 유사하다. 어떤 값을 넣지 않으면 제네릭으로 타입을 명시해주어야 하고,값을 넣게 된다면 타입을 명시하지 않아도 컴파일러가 자동으로 감지한다. asFlow 사용하기두번째로는 asFlow라는 함수를 사용하는 방법이다. listOf("a", "b", "c").asFlow()asFlow 함수는 Iterable, Sequence 등의 확장 함수로 선언되어 있다. flow 람다 사용하기마지막으로는 flow 람다를 사용하는 방법이다..
Flow 개념 살펴보기
·
Study/Kotlin
이번 예시는 팩토리얼 계산 함수를 사용할 예정이다. 일반적 함수 구현fun main() { val result = calculateFactorial(5) println("result: $result")}private fun calculateFactorial(num: Int): BigInteger { var factorial = BigInteger.ONE for (i in 1 .. num) { Thread.sleep(10) factorial = factorial.multiply(BigInteger.valueOf(i.toLong())) } return factorial}이렇게 작성된 함수에서는 계산 결과만 받을 수 있다. 그렇다면 계산 과정은 어떻게 ..
예외 처리에서 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로 바꿔보았다. 실행 결과는 과연..