-
Kotlin Coroutine 은 최근 SharedFlow 와 StateFlow 라는 2가지 type 의 Flow 를 소개했다.
-
LiveData 를 Flow 형태로 바꾸기 전에 LiveData 를 Flow 형태로 바꾸어야 하는 이유를 알아보자.
1. LiveData 는 UI 에 너무 bind 되어 있다.
2. LiveData 는 Android platform 에 너무 bind 되어 있다.
위의 이유로 LiveData 는 Presentation Layer 에서는 사용하기 괜찮을 수 있지만, Domain Layer 로 내려가기에는 ugly 해진다.
Domain Layer 는 platform-independent 해야 하기 때문이다.
-
LiveData 를 pure Flow 로 교체할 수는 없다.
1. Flow 는 .value 가 없다.
2. Flow 는 선언적(Cold)이다. : flow builder 는 flow 가 무엇인지만을 정의하고, collect 가 될 때 생성이 된다. 그래서 collector 가 붙을 때마다 새로운 Flow 가 생성이 되고, 매번 Flow 의 로직이 수행된다. 예를 들어 DB 에 접근하는 작업을 한다면 collect 할 때마다 db 에 접근하는 것이다.
-
위에서 언급한 2번의 문제를 해결하는 것이 SharedFlow 이고, 1번의 문제까지 해결하는 것이 StateFlow 이다.
-
fun <T> Flow<T>.shareIn(
scope:CoroutineScope,
started:SharedStarted,
reply:Int = 0
) : SharedFlow<T> (source)
Flow 의 extension fun "shareIn" 을 통해 SharedFlow 로 변환시킬 수 있다.
scope 은 Flow 를 만들 때 사용하는 scope 을 이야기하며, Data Source 쪽에는 보통 application process 의 LifecycleScope 인 LifecycleCoroutineScope 가 전달된다.
started 에는 SharingStarted.WhileSubscribed() 를 사용할 수 있는데, 이 경우 subscriber 가 0에서 1이 되면 Flow 가 만들어지고 share 를 시작하고, 1에서 0이 되면 share 를 멈춘다.
이는 LiveData 의 onActive, onInActive 와 비슷한 로직이라고 보면 된다.
다른 함수들을 통해 eagerly(즉각적으로 만들고 제거하지 않음), lazily(처음 collect 할 때 만들고, 제거되지 않음) 등의 option 을 선택할 수도 있다.'
reply 는 1을 사용할 수 있는데, 이 때는 새로운 subscriber 가 등록될 때 바로 최신의 값을 내뱉도록 한다.
-
Presentation Layer 에서 LiveData 를 계속 사용하고 싶다면, Flow<T>.asLiveData() 를 사용하면 된다.
-
launchWhenStarted { } 에서 Flow collect 를 한다면, onStart() 에서 collect 가 불리지만, onStop 에서 unsubscribe 가 자동으로 되지는 않는다.
그래서 onStop 에서 unsubscribe 를 해줘야 하는데 이는 매우 귀찮은 일이다.
그래서 coroutine 쪽에서는 observeIn(LifecycleOwner) 라는 extension 을 제공해서 그 안에서 알아서 이 작업을 해준다.
아래와 같이 쓰면 된다.
// Activity
viewModel.locations
.onEach { /* new location received */ }
.observeIn(this)
위와 같이 사용하면 LiveData 의 LifecycleOwner 의존적인 동작과 동일하게 동작한다.
observeIn 으로 인해 LifecycleOwner 의 Lifecycle 이 CREATED 가 되면 coroutine 이 destroy 되고, STARTED 가 되면 recreate 된다.
(Lifecycle.State 에는 INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED 만 있다. PAUSED 와 STOPPED 가 없다. 그래서 onPause() 시 STARTED 로 상태로 돌아가고, onStop() 시 CREATED state 로 돌아가는 구조이다. 그래서 CRETED 가 되면 destory 되고, STARTED 면 recreate 되는 로직인 것이다.)
-
flowOn(Dispatchers.IO) 등을 통해 쉽게 subscribe 하는 thread 를 변경할 수 있다.
-
fun <T> Flow<T>.stateIn(
scope:CoroutineScope,
started:SharingStarted,
initialValue:T
):StateFlow<T>(source)
StateFlow 는 stateIn() extension fun 을 통해 만들 수 있다.
StateFlow 는 확장성은 줄어들고, 특정 목적에 부합하도록 만들어진 SharedFlow 라고 볼 수 있다. (1개 이상의 cache control 등을 할 수 없고, 동일 값이 들어오면 무시한다.(conflate))
StateFlow 는 SharedFlow 의 replay 값이 1로 고정된 것과 같다.
그래서 subscribe 를 하는 순간 latest value 가 무조건 전달된다.
그리고 value 를 접근할 수 있다.
-
끝
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] Overview - Hilt 에 대해 알아보자 (0) | 2022.01.25 |
---|---|
[android] 안전하게 flow 를 collect 하기! (0) | 2021.05.11 |
[RxJava] 햇갈리던 subscribeOn, observeOn 의 thread 관계 정리 (0) | 2021.05.07 |
[android] Write asynchronous DAO queries - Room 에 대해 알아보자 (0) | 2021.05.06 |
[android] Referencing complex data using Room - Room 에 대해 알아보자 (0) | 2021.05.05 |
댓글