▩ 목 차 ▩
1. LiveData vs Flow(StateFlow, SharedFlow, Flow)
1-1. LiveData vs Flow(StateFlow, SharedFlow, Flow)
1-2. StateFlow
1-3. SharedFlow
1-4. StateFlow와 ShareFlow 비교하기
1-5. 정리
다른 사람들의 프로젝트를 보게되면 LiveData 말고 StateFlow를 많이 쓰더라.. 한번 알아보자~~
■ 1. LiveData vs Flow(StateFlow, SharedFlow, Flow) ■
■ 1-1. LiveData vs Flow(StateFlow, SharedFlow, Flow)
MVVM 패턴을 배울때 ViewModel에 연결된 View들이 현재 상태에 알맞게 새로고침되어 표현할 수 있어야 한다.
==> Android에서는 VieModel에서 이러한 실시간 상태 데이터를 다루기 위한 장치(옵저버 패턴)으로 LiveData를 사용을 한다.
LiveData의 큰 장점 중 하나는 액비티티나 프레그먼트 등과 같은 안드로이드 컴포넌트 생명주기를 알고 있기 때문에 편리하게 사용할 수 있다.( 이러한 점 때문에 회전을 해도 데이터가 사라지지 않는 장점을 가짐 )
여기서 문제점이 LiveData는 Lifecycle이 있는 UI(액티비티, 프래그먼트)와 상호작용 하도록 디자인이 되었기 때문에 Repository 같은 레이어에서의 사용이 무리가 있을 것이다... ( 그러니까 왜 UI에게만 집중을 해.. )
[ *Cold Stram 방식 : 상태가 변하지 않는 값을 읽을 때 , 즉 데이터베이스를 읽거나 URL을 통해서 서버 값을 읽는 경우 Cold Stream으로 구현 가능하다. 내가 쉽게 이해한 바로는 1:1로 값을 전달하고, 내가 만든 것을 수행하고 수행후에 종료하는것으로 이해했다.
*Hot Stream 방식 : 0개의 이상의 상대를 향해 지속적으로 값을 전달한다. 내가 쉽게 이해한 바로는 한번 만들면 계속 지속이 되는데 원하는 행동을 할때 그때에 맞춰서 그 결과값을 내어준다고 이해했고 LiveData라고 생각하면 편하다. ]
==> 이것( UI와만 상호작용 하는것)을 해결해주고 LiveData보다 여러 장점이 있는 Observable으로 제공해주는 Flow(순차적으로 값을 배출하고 정상 또는 예외 처리하는 비동기 데이터 스트림) 구현이 있다.
이러한 Flow는 emit()으로 데이터를 배출(입력)하고 Collect로 데이터를 받아오는(출력) 방식이다. 이러한 과정은 비동기 처리가 된다.
이러한 점들을 보면 Flow는 LiveData와 비슷하지만 다른점이 3가지 존재한다.
- 상태를 가지지 않는다.
- Cold Stream 방식(내가 값을 입력을 해주었을때만 생성을 하고 반응을 함)이기 때문에, 연속으로 데이터를 처리할 때마다 Flow를 호출한다. (연속적으로 들어오는 데이터를 처리할 수 없다는 말)
- 스스로 라이프사이클을 알지 못한다.
위에서 말한 3가지는 차이점이자 단점이라고 말할 수 있다. 이러한 단점들을 보완하기 위해 나온 것들이 있었는데 바로,
1,2번 단점을 보완한 것 ==> StateFlow, SharedFlow
3번 단점을 보완한 것 ==> lauchWhenStarted 이다.
■ 1-2. StateFlow
먼저 StateFlow를 살펴보자.
- LiveData와 동일한 기능이며 실시간 상태 데이터를 다루기 위한 장치이다.
- StateFlow는 Flow와 달리 상태(Value)를 가지고, Hot Stream이다. 또한 초기값을 가지고 마지막 값의 개념이 있다.
- 중요한 점은 업데이트 된 경우에만 반환하고 중복(이전 값과 비교하여 동일한 값이 들어오지 않는 경우)으로 값을 가지고 오면, collect() 해오지 않는다.
- Hot Stream 이다 보니, 종료가 되지 않는다. 즉, collect 함수를 호출하더라도 정상적으로 종료되지 않고, lauchIn 함수를 호출하더라도 정상적으로 종료되지 않는다. 그렇기에 UI가 화면에 표시되지 않을때(백그라운드에 있을때) collecting 할 때 주의를 해야하며, 수동으로 중지를 시킬 수 도 있다.
- LiveData와 같이 데이터바인딩을 통해 직접 바인딩 해줄 수 있고, 여러 함수들을 사용하여 데이터를 다양하게 처리할 수 있다.
- LiveData와 동일하게 xml에서 바인딩해주고, lifecycleOwner를 정의해주면 LiveData와 동일하게 UI가 자동으로 갱신된다.
위에 있는 점들을 보게되면 LiveData와 StateFlow는 별 차이가 없어보인다. 초기값 설정(LiveData : 초기값 x, StateFlow : 초기값 : o ) 에서만 있을 것 같지만,
하지만 클린아키텍처 관점에서는 큰 차이가 있다.
클린아키텍쳐의 구조는 아래와 같이 되어 있다.
- UI 계층 : View, ViewModel 등등
- Domain 계층 : Repository(interface), UseCase 등등
- Data 계층 : Repository(implement), DateSource 등등
클린 아키텍쳐의 목적인 의존성 관계를 명확히 하여 유지보수, 동작구조 등의 파악을 쉽게 하기 위해 Presentation 계층 -> Domain 계층, Data 계층 -> Domain 계층, Presentation 계층 -> Data 계층의 의존성을 가진다.
즉, Domain 계층은 Presentation, Data 계층으로의 의존성을 가지면 안되기에 순수한 Kotlin 코드로만 구성 되어야 한다.
==> 이 말을 다시 생각해서 풀어본다면, LiveData는 안드로이드 플랫폼의 기능이기 때문에 플랫폼 종속성을 가지고 있고, Presentation 계층에서 관리되기 때문에 Presentation 계층이 아니라면 LiveData 대신 Flow(StateFlow)를 사용해야만 한다는 것이다.
■ 1-3. SharedFlow
다음으로 SharedFlow를 살펴보자.
- 일회성 이벤트를 UI로 보내려고 할 때 주로 사용하는 장치이다.
- StateFlow의 일반화된 버전으로 볼 수 있으며, StateFlow와 같이 Hot Stream이다.
- StateFlow와 다르게 초기값을 가지지 않고, 여러 설정이 가능하기 때문에 주로 이벤트 처리에 사용할 수 있다.
- SharedFlow 생성시에 조건을 줄 수 있다. 다음과 같다.
- replay : 새로운 구독자들에게 이전 이벤트 방출여부 ( 0 : 방출 안함, 1 : 방출 함 )
- extraBufferCapacity : 추가 버퍼 생성 여부 ( 1 : 생성 )
- onBufferOverflow : 버퍼 초과시 처리 여부( DROP_ORDEST = 가장 오래된 데이터 삭제)
■ 1-4. StateFlow와 ShareFlow 비교하기
- StateFlow는 반드시 초기값을 가진다. ( 단, 한 개의 최신 상태값을 가진다.)
- StateFlow는 value 속성을 이용해 값을 방출할 수 있다.
- ShareFlow는 초기값이 없으며, 조금 더 디테일한 설정값들을 생성자에 전달해 줄 수 있다.
- StateFlow의 값은 업데이트 된 경우에만 반환하고, 중복(이전 값과 비교하여 동일한 값이 들어오지 않는 경우)으로 내보낼 경우, collect() 해오지 않는다. ==> 이러한 점 때문에 이벤트 처리에 사용하기에 부적절하고, LiveData와 같이 실시간 상태 데이터를 다루기 위한 장치에 적합하다.
- SharedFlow는 모든 콘텐츠가 주기적으로 동시에 새로고침 되도록 앱의 나머지 부분에 전송할 수 있다. (EX : 최신 뉴스 가져오기)
- API 오류가 발생할 때 Toast 메세지로 띄어준다고 할 때,
StateFlow로 만들게 되면, API 오류가 있을때 Toast메세지가 띄어지게 되고, 화면이 회전하고 다시 뷰가 재생성 될 때 Toast 메세지가 반복해서 띄어지는 것을 알 수 있다.(StateFlow는 화면 회전시 값을 다시 방출함)
SharedFlow로 만들게 되면, API 오류가 있을때만Toast메세지는 띄어지게 된다.(SharedFlow는 화면 회전시 값을 다시 방출하지 않음) - SharedFlow는 특정 사용자 작업이 발생하거나 API 응답을 받을 때 일회성 이벤트를 보내는데 사용되는 것이다.(이벤트를 UI로 배내려고 할 때)
- StateFlow는 계속해서 변화되는 값을 받아오고 싶을때 쓰는것이라고 생각하면 된다.
- Flow는 타이머라고 생각하면 된다. 우리가 정해준 시간동안 할 일을 끝내면 Flow는 아무런 일을 하지 않기 때문이다.
■ 1-5. 정리
- LiveData는 UI와 밀접한 관계이고, Flow는 데이터 통신과 밀접한 관계이기 때문에 직관적으로도 Flow를 사용하는 것이 좋고, 많은 데이터 처리에도 유리하다.
- 클린아키텍처 관점에서 LiveData는 플랫폼 종속적이므로 Domain 계층에 사용할 수 없지만 Flow는 사용할 수 있다.
- Flow는 결과를 필터링하는 다양한 기능을 하는 함수들을 사용할 수 있다.
- Flow는 보완이 되어 lifecycle에 종속시킬 수 있고, JetPack Compose 에서는 xml에서 벗어난 선언형 프로그래밍으로 바인딩 개념이 점차 옅어지고 있으므로 LiveData는 Flow로 대체가 가능 할 것이라 본다.
- 계속해서 변화하는 값이 있을때 LiveData를 사용하지 말고 StateFlow를 권장을 하며 일회성 이벤트를 UI로 보내려고 할때는 SharedFlow를 사용하고 우리가 정해준 시간동안 할 일을 부여하고 싶으면 Flow를 사용하면 되는것으로 이해하면 편할 것이다.
- Cold Flow는 내가 만든 것을 수행하고 종료하는것으로 이해하면 되는것이고, Hot Flow는 한번 만들면 계속 지속이 되는데 원하는 행동을 할때 그때에 맞춰서 그 결과값을 내어준다고 생각하면 쉽다.
참고