본문 바로가기

Android 공부

32. Kotlin Flow 도입하기

 

새롭게 시작하는 프로젝트에 평소에 사용하던 LiveData 대신 Flow 로 데이터를 처리해보고 싶어서 Flow 를 도입해보았다. 기본적인 문법을 단순히 정리하는 것보다 어려움을 겪었던 부분에 대해서 정리해보려 한다.

 

 

 

collect 와 collectLatest


  • collect

collect 를 보면 suspend 함수를 사용하여 emit 된 이벤트를 순차적으로 소비하는 함수이다. 이때 emit 속도 > collect 속도라면, 데이터의 소비가 느려질 수 있다. 즉 데이터가 발행되는 속도가 소비되는 속도보다 더 빠르다면 발행된 데이터가 바로 소비되지 못하고 기다리게 되는 것이다. 이렇게 되면 새로운 데이터가 발행되어도 이전의 데이터부터 순차적으로 소비하기 때문에 최신의 데이터로 ui 를 바로 그려야 하는 상황에서 문제가 발생할 수 있다.

 

  • collectLatest

위와 같은 문제가 발생했을 때, collectLatest 로 최신의 데이터를 바로 소비하게 할 수 있다. collect 와는 다르게 새로운 데이터가 발행되면 이전의 데이터처리를 멈추고 새로운 데이터를 소비한다. 최신 데이터를 이용하여 UI 를 구현해야하는 상황 등에 주로 사용할 수 있다.

 

public suspend fun <T> Flow<T>.collectLatest(action: suspend (value: T) -> Unit) {
    /*
     * Implementation note:
     * buffer(0) is inserted here to fulfil user's expectations in sequential usages, e.g.:
     * ```
     * flowOf(1, 2, 3).collectLatest {
     *     delay(1)
     *     println(it) // Expect only 3 to be printed
     * }
     * ```
     *
     * It's not the case for intermediate operators which users mostly use for interactive UI,
     * where performance of dispatch is more important.
     */
    mapLatest(action).buffer(0).collect()
}

 

물론 이러한 collectLatest 가 문제가 없는 것은 아니다. 일부 상황에서 중간 데이터를 하나도 얻지 못하고 마지막에 들어온 데이터만 얻는 문제가 발생하기도 한다. 이를 해결하기 위해 한 번 시작한 데이터 소비는 끝까지 이루어지도록 하는 conflate 함수를 사용할 수 있다. 이는 이후에 다시 정리하겠다.

 

 

 

SharedFlow 의 파라미터


 

sharedFlow 에 여러 파라미터를 주어 원하는 동작을 실행할 수 있다. 아래는 sharedFlow 의 파라미터와 각각의 역할이다.

  • replay
    • 새로운 수신자(subscriber)가 등록될 때 이전 이벤트를 재생하는지 여부.
    • 즉 최신의 이벤트만 처리하고 싶으면 값을 0으로 주어야 함.
    • 데이터를 collect 할 때 전달받을 이전의 데이터 개수를 설정할 수 있고 몇 개를 캐싱하고 있을 지를 인자로 제공해야 함.
  • extraBufferCapacity
    • buffer 개수 정하는 옵션.
    • flow의 emit이 빠르고 collect가 느릴 때 지정된 개수만큼 buffer에 저장되며 지정된 개수가 넘어가면 onBufferOverflow 정책에 따라 동작.
  • onBufferOverflow
    • buffer 가 다 찼을 경우 정책.
      • SUSPEND : emit 코드가 blocking
      • DROP_OLDEST : 버퍼 안의 오래 된 데이터부터 삭제
      • DROP_LATEST : 버터 안의 최신 데이터부터 삭제

 

sharedFlow 를 사용하면서 실제로 파라미터를 제대로 설정하지 않아 문제를 겪기도 했다. replay 옵션을 1로 주면서 화면 전환 이벤트를 관리하다보니, 이전의 event 를 1개를 sharedFlow 가 캐싱하고 있어 제대로 화면 전환이 되지 않았다. 이때 replay 파라미터를 0으로 주어 문제를 해결할 수 있었다. 

 


 

Flow 가 본격적으로 사용된지 그리 오랜 시간이 지나지 않은 것으로 알고있다. 그래서 그런지 다른 개념에 비해 다양한 예제나 문제의 원인을 찾기 어려워 직접 해보면서 많은 개념을 깨달은 것 같다.

 

kotlin Flow 를 도입하면서 왜 LiveData 가 아니라 Flow 를 사용했는가? 에 대한 답을 고민해보았다. 이 고민은 다음 게시물에서 자세하게 풀어나가겠다.

'Android 공부' 카테고리의 다른 글

31. LiveData postValue vs setValue  (0) 2023.09.17
30. Navigation Component  (0) 2023.09.03
29. JVM 구조  (0) 2023.08.11
28. 안드로이드 Room Migration  (0) 2023.02.22
26. 안드로이드 Bundle & Parcelable  (0) 2023.02.16