[Android] Kotlin and Flow usage
#
Flow 는 'emit' 으로 data 를 발행하고, 'collect' 로 data 를 받아본다.
#
DataStore, Retrofit, Room, WorkManager 등에서 Flow 를 지원하고 있다.
#
flow builder 로 flow 를 쉽게 만들 수 있으며 이 녀석은 suspend block 을 받는다.
#
collect 역시 suspend block 을 받는다.
#
final operator 가 지정되기 전까지 flow 는 emit 하지 않으며,
downstream 순서대로 로직이 수행된다.
#
Android UI 에서 collect 를 사용하기 위해서는 아래와 같은 방법이 사용된다.
Flow.asLiveData():LiveData // 아래 2개를 추천함
Lifecycle.repeatOnLifecycle(state)
Flow.flowWithLifecycle(lifecycle, state)
#
lifecycleScope.launch{
repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.userMsgs.collect { msgs ->
listAdapter.sumitList(msgs)
}
}
}
지정한 lifecycle 에 진입하면 새로운 coroutine 을 만들며 collect 를 시작하고,
해당 lifecycle 에서 벗어나면 collect 하던 coroutine 을 cancel 시킨다.
#
repeatOnLifecycle 은 호출한 coroutine 을 suspend 시키고, Lifecycle 이 destroy 되어야 resume 이 된다.
collect 가 suspend function 이기 때문에 여러개의 flow 를 collect 하기 위해서는 launch 를 각각 해줘야 한다.
lifecycleScope.launch{
repeatOnLifecycle(Lifecycle.State.STARTED){
launch{
viewModel.userMsgs.collect{ ... }
}
launch{
otherFlow.collect{ ... }
}
}
}
#
lifecycleScope.launch{
viewModel.userMsgs
.flowWithLifecycle(lifecycle, State.STARTED)
.collect { msgs ->
liadAdapter.sumitList(msgs)
}
}
위의 repeatOnLifecycle 과 같은 기능이다.
(돼왕 : flowWithLifecycle 은 내부적으로 repeatOnLifecycle 을 사용한다. 따라서 single flow 를 collect 할 때 유용하며, multiple flow 를 collect 할 때는 repeatOnLifecycle 이 추천된다.)
#
lifecycleScope.launch{
viewModel.userMsgs.collect{ msgs ->
listAdapter.submitList(msgs)
}
}
위 코드는 앱이 bg 상태에 가도 collect 를 계속 한다.
#
launchWhenX (ex. launchWhenStarted) 는 collect 는 멈추지만 emit 은 계속 진행되는 문제가 있다.
(돼왕 참고 : https://aroundck.tistory.com/7738)
#
StateFlow 는 buffer 역할을 하여 latest 값을 유지할 수 있다.
flow builder 로 만든 것을 collect 하면 flow block 을 처음부터 다시 태운다. 그러나 StateFlow 는 latest 값을 전달해준다.
#
private val _myUiState = MutableStateFlow()
val myUiState = StateFlow = _myUiState
init{
viewModelScope.launch{
_myUiState.value = Result.Loading
_myUiState.value = repository.fetchStuff()
}
}
위와 같이 설정해서 쓸 수 있다.
#
flow 를 StateFlow 로 변경하기 위해서는 stateIn 함수를 사용하면 좋다
val result:StateFlow<Result> = someFlow
.stateIn(
initialValue = Result.Loading
scope = viewModelScope,
started = WhileSubscribed(5000),
)
WhileSubscribed(5000) 은 앱이 bg 상태에 들어가도 upstream flows 를 5초동안 지속시킨다.
(돼왕 : WhileSubscribe() 함수는 active observer 가 없을 때 producer 를 멈추는 함수이며, 여기에 time 인자가 들어가면 subscribe 가 안 되어도 time 시간동안 producer 를 연명시키는 것이다.)
그래서 예를 들어 screen orientation change 등에서는 보통 5초안에 앱이 다시 resume 되기 때문에 upstream 이 끊기지 않고, home button 등으로 bg 상태가 된 경우네는 5초 후에 upstream 이 끊기는 효과를 볼 수 있다.
끝
참고 : https://youtu.be/fSB6_KE95bU