본문 바로가기
Android/Flow

Coroutine Flow(3) LiveData vs StateFlow

by 태크민 2023. 7. 3.

LiveData

LiveData는 Lifecycle 라이브러리 중 하나로, 안드로이드 공통의 라이프사이클과 관련된 문제를 해결할 수 있게 해주면서 앱 개발시 보다 더 유지보수하기 쉽게, 테스트하기 쉽게 만들어주는 라이브러리이다.

 

LiveData는 Observer 패턴을 활용하여 구현되었으며, 관찰 가능한 일반 클래스인 ObservableXXX 클래스와는 달리 LiveData는 생명주기의 변화를 인식한다. 즉, Activity, Fragment, Service 등 안드로이드 컴포넌트의 생명주기 인식을 통해 Active 상태에 있는 컴포넌트에서만 업데이트를 한다.

 

LiveData의 장점

  • Activity와 Fragment는 LiveData 객체를 안전하게 관찰할 수 있고, 생명주기가 끝나는 즉시 관찰을 멈추기 때문에 누수를 걱정하지 않아도 된다.
  • LiveData는 Observer 패턴을 따르기에 LiveDate는 관찰 대상인 데이터가 변경될 때 Observer 객체에 알린다. 그리고 Observer 객체를 통해 UI를 업데이트한다면 개발자가 직접 업데이트할 필요가 없게 된다.
  • Activity가 Back Stack에 있을 때를 비롯하여 Observer의 생명주기가 비활성 상태에 있으면 Observer는 어떤 LiveData 이벤트도 받지 않아 비정상 종료가 발생하지 않게 된다.
  • 생명주기가 비활성화(Inactive)되었다가 다시 활성화(Ative)될 때 최신 데이터를 수신한다.
  • Room이나 Retrofit 라이브러리 등과 호환되어 함께 사용하기 좋다.

위 내용을 봤을 때, LiveData는 단순히 옵저버 패턴을 통해 데이터의 변화를 관찰하고 UI를 업데이트하기에 용이하다는 것을 넘어 Activity나 Fragment 등의 생명주기에 따른 관리도 잘해주는 라이브러리라는 것을 알 수 있다.

 

그렇기에 꼭 MVVM 디자인 패턴이 아니더라도 데이터를 관리하는데에 지금까지도 굉장히 많이 사용되고 있으며, 주로 함께 사용하는 라이브러리로는 AAC DataBinding, AAC ViewModel 등이 있다.

 

클린 아키텍처 관점에서의 LiveData

위 그림은 클린 아키텍처를 안드로이드 개발 관점에서 재 구성하여 그림으로 표현한 것이다.

클린 아키텍처에서 계층 간의 의존성은 한쪽으로만 발생하여야 한다. 예컨대, Presentation 계층에서는 Domain 계층을 알지만, 그 반대인 Domain 계층은 Presentation 계층을 알면 안된다.

 

이번 포스팅에서는 클린아키텍처에 대한 내용을 주로 다루기보다는, LiveData와 StateFlow에 대해 중점적으로 살펴볼 것이니 아키텍처와 관련한 자세한 설명은 생략하고 간단하게만 살펴보겠다.

 

Presentation Layer

화면과 입력에 대한 처리 등 UI와 관련한 부분을 담당한다. Activity, Fragment, View, ViewModel 등을 포함한다.

여기에서 Activity와 Fragment는 View의 역할을 하는, 다시 말해 데이터를 소유하는 것이 아니라 데이터를 표시하기만 하는 역할을 하므로 LiveData 인스터스를 보유해서는 안된다.

 

LiveData 객체는 주로 AAC ViewModel에서 관리하게 되는데, 이 또한 Presentation Layer에 속해 있으니 크게 문제가 될 것은 없어 보인다.

그리고 Presentation Layer는 Domain Layer에 대한 의존성을 가지고 있다.

 

Data Layer

Domain Layer에 대한 의존성을 갖는다. Domain 계층의 Repository 인터페이스를 포함하고 있으며, 이에 대한 구현을 Data Layer에서 하게 된다. 그리고 데이터베이스(Local)와 서버(Remote)와의 통신도 Data 계층에서 이루어진다. 또한 필요하다면 Mapper 클래스를 두어 Data Layer의 모델을 Domain 계층의 모델로 변환하게 해주는 역할도 이 계층에서 하게 된다.

 

Data Layer 클래스에서 LiveData 객체를 작업하고 싶을 수 있지만 LiveData는 비동기 데이터 스트림을 처리하도록 설계되지 않았다.

안드로이드의 교과서인 Developer 사이트에서도 이에 대해 명시하고 있으며, Repository에서는 LiveData를 사용하지 않도록 권장하면서 동시에 Kotlin Flow를 사용하도록 권장하고 있다. (참고)

 

Domain Layer

어플리케이션의 비즈니스 로직에서 필요한 UseCase와 Model을 포함하고 있다.

UseCase는 각 개별 기능 또는 비즈니스 논리 단위이며, Presentation Layer, Daya Layer 계층에 대한 의존성을 가지지 않도 독립적으로 분리되어 있다.

 

Domain 계층은 안드로이드에 의존성을 가지지 않은 순수 Java 및 Kotlin 코드로만 구성한다. 여기에는 Repository 인터페이스도 포함되어 있다.

 

LiveData의 문제는 여기서도 발생한다. 우리는 너무나 자연스럽게 이 Domain Layer에서 LiveData를 사용하곤 하는데, 만약 계층 별로 멀티 모듈로 프로젝트를 구성하고 있다면 단지 LiveData만을 위해서 안드로이드 의존성을 가지도록 해야할 수도 있게 된다. 그리고 LiveData는 안드로이드 SDK에 포함되어 있따보니 단위 테스트를 할 때도 이를 위한 별도의 테스트 지원 모듈을 의존해야한다.

 

요약을 하자면 클린아키텍처 관점에서 LiveData의 문제점은 아래와 같다.

  • LiveData는 UI에 밀접하게 연관되어 있기 떄문에 Data Layer에서 비동기 방식으로 데이터를 처리하기에 적절하지 않다.
  • LiveData는 안드로이드 플랫폼에 속해 있기 때문에 순수 Java / Kotlin을 사용해야하는 Domain 계층에서 사용하기에 적합하지 않다.

d안드로이드 개발 언어로 코틀린이 자리 잡기 전까지 위와 같은 문제점을 안고 있으면서도 안드로이드 진영에서는 별다른 선택권이 없었다. 그러나 코틀린 코루틴이 발전하면서, Flow가 등장하게 되었고 많은 안드로이드 커뮤니티에서는 이 Flow를 이용해서 LiveData를 대체할 수 있을지에 대한 기대가 생기기 시작했다.

그러나 Flow를 통해 LiveData를 대체하는 것은 쉬운일이 아니였다.

그 이유는

  • Flow는 스스로 안드로이드 생명주기에 대해 알지 못한다. 그래서 라이프사이클에 따른 중지나 재개가 어렵다.
  • Flow는 상태가 없어 값이 할당된 것인지, 현재 값은 무엇인지 알기가 어렵다.
  • Flow는 Cold Stream 방식으로, 연속해서 계속 들어오는 데이터를 처리할 수 없으며 collect 되었을 때만 생성되고 값을 반환한다.

이를 위해 등장한것이 바로 StateFlow이다.

 

StateFlow

StateFlow는 현재 상태와 새로운 상태 업데이트를 collector에 내보내는 Observable한 State holder flow이다. 그리고 LiveData와 마찬가지로 value 프로퍼티를 통해서 현재 상태 값을 읽을 수 있다.

 

StateFlow와 LiveData는 둘 다 관찰 가능한 데이터 홀더 클래스이며, 앱 아키텍처에서 사용할 때 비슷한 패턴을 다룬다. 즉 MVVM에서 LiveData 사용되는 자리에 StateFlow로 대체할 수 있다. 

 

그러나 StateFlow와 LiveData는 다음과 같이 다르게 작동한다.

  • StateFlow의 경우 초기 상태를 생성자에 전달해야 하지만, LiveData의 경우는 전달하지 않아도 된다.
  • View가 STOPPED 상태가 되면 LiveData.observe()는 Observer를 자동으로 등록 취소하는 반면, StateFlow는 자동으로 collect를 중지하지 않는다. 만약 동일한 동작을 실행하려면 Lifecycle.repeatOnLifecycle 블록에서 흐름을 수집해야 한다.

 

위와 같은 차이가 있지만,

LiveData 대신 StateFlow를 사용했을 때의 이점은 다음과 같다.

  • 안드로이드 플랫폼에 종속적이었던 LiveData와 달리, StateFlow는 순수 Kotlin라이브러리이기 때문에 Domain Layer에서 사용할 수 있다.
  • 코루틴을 통해 Work Thread에서도 비용이 많이 드는 데이터 스트림을 처리할 수 있기 때문에 Data Layer에서 LiveData를 사용하는 것보다 향상된 성능으로 사용 가능하다.
  • StateFlow는 zip, flatMapMerge 등 다양한 Flow API를 사용할 수 있기 때문에 LiveData 보다 풍부하게 사용할 수 있다.

 

 

출처

https://readystory.tistory.com/207

 

 

 

 

'Android > Flow' 카테고리의 다른 글

Coroutine Flow(4) - 총정리  (0) 2023.07.03
Coroutine Flow(2) - StateFlow, SharedFlow  (0) 2023.06.30
Coroutine Flow(1) - Flow 란  (0) 2023.06.27