LiveData vs StateFlow

StudyBug·2025년 3월 29일
post-thumbnail

안드로이드 공식 개발 문서에서 최신 앱 아키텍처로 UI 상태 관리 및 데이터 레이어와의 상호작용을 구현할 때 Coroutine Flow와 State Holder 사용을 권장하고 있다. 이에 따라, 나도 UI 상태를 ViewModel로부터 가져와 화면에 표시할 때 StateFlow를 사용하여 작업하였다. 하지만 단순히 값을 화면에 보여주는 것이라면 LiveData도 Observer를 통해 데이터를 관찰할 수 있는 기능이 있어 사용하는데 적합하다는 생각이 들었다.

UI 상태 관리에 있어 LiveData도 적합한 거 같은데, 공식 문서에서 StateFlow 사용을 명시적으로 권장하는 것을 보며, StateFlow가 LiveData를 온전히 대체할 수 있어서 그런걸까? 의문이 생겼다. 따라서, LiveData와 StateFlow에 대해서 알아보고 StateFlow가 LiveData보다 우세한지 알아보려 한다.

LiveData

LiveData는 데이터를 효과적으로 관리하기 위한 관찰 가능한 데이터 홀더 클래스이다. LiveData는 안드로이드 컴포넌트의 생명 주기를 인식하여, 생명 주기가 활성 상태(Started 또는 Resumed)일 때 데이터를 제공할 수 있다. 활성 상태의 컴포넌트가 LiveData를 관찰할 때, LiveData가 업데이트 되면 데이터를 관찰자를 통해 컴포넌트에 전달한다. 이렇게 특정 조건에서 데이터를 제공하는 LiveData의 특징은 다음과 같다.

  • 최신 값 제공

    • LiveData는 컴포넌트가 비활성 상태에도 업데이트 되어 최신 값을 유지한다. 컴포넌트의 수명 주기가 활성 상태로 변하거나 활성 상태에서 LiveData의 값이 변경된다면, 최신 값을 관찰자에게 제공한다.
  • 온전한 업데이트 이력 확인 불가

    • 관찰자를 LiveData에 등록해놨어도 컴포넌트가 비활성 상태라면 업데이트 되는 값을 얻을 수 없어서 알 수 없다. 이때 LiveData가 기존에 가지던 값은 업데이트 되면서 아예 사라지기 때문에 업데이트 이력을 순차적으로 확인할 수 없게 된다.
  • 메모리 누수 방지

    • LifeCycleOwner는 컴포넌트의 생명주기를 관리하는 인터페이스인데, LiveData에 관찰자를 등록할 때 관찰자가 속한 컴포넌트도 LifeCycleOwner에 같이 등록된다. 여기서 컴포넌트가 소멸될 경우, 이 컴포넌트가 사용하는 관찰자들이 자동으로 LiveData에서 해제되어 메모리 누수를 방지하고 앱의 안정성을 높인다.
  • 필요한 UI만 업데이트

    • 활성 상태일때 자신을 관찰하는 관찰자에게만 최신 값을 전달하므로 이 관찰자를 사용하는 UI만 업데이트 할 수 있다. 따라서 불필요한 UI 업데이트를 최소화 할 수 있다.
  • 직접적인 코루틴 사용 X

    • LiveData는 컴포넌트의 생명주기를 인식하고 UI와 데이터를 효율적으로 동기화하기 위해 설계되었다. 이 때문에 비동기 데이터 스트림을 직접적으로 처리하는 기능이 내장되어 있지 않다. 비동기 작업을 수행하려면 코루틴을 실행하고 결과를 LiveData에 넣어야 하는데, 이는 코드 복잡도를 증가시키고 성능 저하를 유발할 수 있다.
  • 호환성

    • Java, Kotlin으로 LiveData를 사용하는데 문제가 없다. 그러나 LiveData는 컴포넌트의 생명주기에 의존적이기 때문에 안드로이드 플랫폼과 독립적으로 작용하는 계층인 도메인 계층, 데이터 계층에서 사용하기 어렵다.

StateFlow

Coroutine Flow는 Kotlin에서 비동기적으로 데이터를 처리하기 위한 도구이다. 그중 StateFlow는 UI 상태 관리와 같이 지속적인 상태 업데이트가 필요한 상황에서 사용되는 Coroutine Flow의 한 형태이다. StateFlow는 지속적인 업데이트를 통해 데이터를 항상 최신으로 유지한다. 최신 값을 유지하는 StateFlow의 특징은 다음과 같다.

  • 핫 플로우(Hot Flow)

    • 구독자는 StateFlow가 방출하는 데이터를 수신하고 UI 업데이트, 데이터 처리 등의 작업을 수행하는 코드이다. Hot Flow는 구독자가 있든 없든 항상 데이터를 생성하고 최신 상태로 유지하여 구독자가 나타났을 때 최신 값을 제공한다. 이러한 Hot Flow의 특징 때문에 StateFlow는 데이터의 생성과 소비를 독립적으로 할 수 있으며, 최신 값을 제공할 수 있다.
  • 메모리 누수

    • StateFlow는 자체적인 수명 주기를 가지지 않는다. 그래서 StateFlow를 구독하는 코루틴을 명시적으로 취소하지 않으면 해당 코루틴이 StateFlow가 방출하는 값을 수신하려고 하기 때문에 메모리 누수가 발생할 수 있다. 하지만 코루틴이 컴포넌트의 수명 주기를 따르게 한다면 이런 메모리 누수를 방지할 수 있다.
    • 예를 들어, UI계층에서 collectAsStateWithLifeCyfcle()를 통해 StateFlow 데이터를 수집하면 코루틴은 컴포저블의 생명 주기에 따라 자동으로 관리된다. 따라서 컴포저블이 소멸될 때 코루틴도 소멸하여 StateFlow의 수집을 자동으로 중단하고 메모리 누수를 방지할 수 있다.
  • 안전한 상태 업데이트

    • MutableStateFlow는 StateFlow의 값을 변경할 수 있는 형태이다. MutableStateFlow의 value 속성은 값을 일관된 상태로 유지할 수 있는 atomic한 특성을 지닌다. 따라서 MutableStateFlow의 value 속성을 통해 값을 안전하게 업데이트할 수 있다.
  • 상태 홀더(State Holder)

    • StateFlow의 값이 업데이트 됐을 때, 상태 홀더는 업데이트 된 값을 방출하고 이 값을 수집하는 모든 collecter에게 업데이트된 값을 전달한다. 이에 따라 컴포넌트들이 변화에 실시간으로 반응하게 한다.
  • 코루틴 기반

    • StateFlow는 코루틴을 기반으로 작동하여 비동기 코드를 쉽고 간결하게 작성할 수 있다. 예를 들어, 네트워크 통신 이전에 StateFlow의 값을 먼저 업데이트 해야 하는 경우, 비동기적으로 동작하는 코드 내에서 코루틴의 suspend함수를 통해 작업 순서를 보장할 수 있다.
  • 호환성

    • 안드로이드 앱 개발에서 Kotlin과 Java를 함께 사용하는 프로젝트에서 StateFlow를 사용해야할 경우, 효율적으로 활용하기 위해 호환성이 중요하다. Java는 코루틴 기능을 사용하지 못하므로 StateFlow를 직접적으로 사용할 수 없다. 하지만 Kotlin을 통해 StateFlow 데이터를 처리하고 해당 데이터를 Java에서 사용할 수 있는 형태로 변환하여 Java와 간접적으로 호환이 가능하다.

결론

LiveData와 StateFlow의 공통점

  • 최신 값 제공

    • LiveData는 활성 상태일 때 관찰자에게 최신 값을 전달하고 StateFlow는 Hot Flow의 특성을 통해 최신 값을 유지하고 State Holder를 통해 구독자에게 최신 값을 전달한다.
  • 메모리 누수 방지

    • LiveData는 관찰자가 속한 컴포넌트의 소멸에 따라 자동으로 관찰자를 해제하고, StateFlow은 코루틴 내에서 실행되어 코루틴 스코프를 실행하는 구독자가 있는 컴포넌트가 소멸할때 자동으로 코루틴 스코프를 종료하여 StateFlow 수집을 해제한다.
  • 필요한 UI만 업데이트

    • LiveData는 관찰자에게만 최신 값을 전달하여 해당 관찰자를 등록한 UI들만 업데이트하고, StateFlow는 구독자에게만 최신 값을 전달하여 구독자가 있는 UI만 업데이트 한다.

LiveData와 StateFlow의 차이점

  • 업데이트 이력 확인

    • LiveData는 컴포넌트가 비활성 상태일 때 업데이트 된 값을 얻을 수 없어 중간에 업데이트 된 이력을 놓칠 수 있지만, StateFLow는 매번 바뀔 때마다 데이터를 뽑아낼 수 있어 전체 업데이트 이력을 확인할 수 있다.
  • 비동기 작업 처리

    • LiveData는 비동기 데이터 스트림의 부재로 코루틴에서 비동기 작업을 하고 LiveData에 결과를 얻어와야 하지만, StateFlow는 코루틴을 기반으로 하기 때문에 비동기 작업 처리를 바로 진행할 수 있다.
  • 생명주기

    • LiveData는 컴포넌트의 생명주기에 의존적이기 때문에 도메인 계층, 데이터 계층에서 사용하기 어렵지만, StateFlow의 생명주기는 독립적이기 때문에 도메인 계층, 데이터 계층에서 사용하기 쉽다.
  • 호환성

    • LiveData는 Java, Kotlin과 원활하게 호환되고, StateFlow는 Kotlin과 호환되지만, Kotlin에서 Java가 사용할 수 있는 데이터로 사용하기 위해서는 추가적인 작업이 필요하다.

반드시 StateFlow를 사용해야 할까?

위에 제시된 LiveData와 StateFlow의 차이점을 보면 StateFlow가 LiveData보다 비동기 작업 처리, 계층 간 의존도, 코드 복잡도 측면에서 모두 우세하고 데이터의 변화를 언제든지 확인할 수 있어서 확실히 더 좋다.

하지만 StateFlow는 최신 값을 유지하므로 사용 시 메모리 사용량이 증가하고 LiveData는 활성/비활성 상태가 있는 것으로 보아 비활성 상태일 땐 메모리를 효율적으로 관리할 수 있다. 더불어, 안드로이드 앱은 초기에 Java로 만들어지기 시작했기 때문에 Java와의 호환성도 중요한데, LiveData가 그 연결 고리가 되어줄 수 있다.

따라서 단순 UI 작업에 해당하는 데이터 업데이트 혹은 Java와의 호환성이 고려되는 경우에는 LiveData를 사용하고, 그 외의 경우에는 StateFlow를 사용해 계층 간 의존도와 코드 복잡도를 낮추고 코드의 가독성과 유지보수성을 챙기는 것이 합리적일 것이다.

참고 자료

https://developer.android.com/topic/architecture?hl=ko

https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=ko

https://developer.android.com/topic/libraries/architecture/livedata?hl=ko

profile
갈 길이 먼 개발자 꿈나무

0개의 댓글