<aside> <img src="/icons/emoji-sunglasses_orange.svg" alt="/icons/emoji-sunglasses_orange.svg" width="40px" /> StateFlow와 SharedFlow의 대한 정리를 보시려면 클릭하세요!
</aside>
예시를 하나 들어보자.
서버에서 받아올 데이터가 많다고 가정하고(약 2~3초 동안 데이터를 받아온다고 하자.) 해당 데이터가 다 받아 와야 화면이 보여지는 구조이다.
StateFlow
를 사용하면 위 상태를 크게 3가지의 상태로 나타낼 수 있다.
위 상태들을 sealed class
로 관리하자. - 링크의 sealed class 부분을 참고.
상위 클래스를 상속한 하위 클래스의 정의를 제한할 수 있다.
서버에서 데이터를 받아오는 response가 성공과 실패에 따라 제공해주는 데이터가 다르다고 가정하자.
sealed class UiState {
object Init() : UiState()
data class IsLoading(val isLoading: Boolean) : UiState()
data class IsSuccess(val successDto: SuccessDto) : UiState()
data class IsFailed(val failedDto: FailedDto) : UiState()
data class ShowToast(val message: String) : UiState()
}
음.. 상태는 정의했는데, 이걸 어떻게 사용해야할까?
생각해보자. StateFlow
는 최신의 하나의 상태를 가질 수 있고, 생성자를 사용해 초기값을 만들 수 있다.
아! 그러면 생성자에 초기 상태를 지정해주고, 앱 흐름에 따라 상태값을 변경해주면 되겠군!
코드로 살펴보자.
// ViewModel
private val _uiState: MutableStateFlow<UiState> = MutableStateFlow(UiState.Init)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun getResponse() {
viewModelScope.launch {
useCase()
.onStart { setLoading() }
.catch { exception ->
hideLoading()
showToast(exception.message.toString())
}
.collect { response ->
hideLoading()
when(response) {
is UiState.IsSuccess -> { ... }
is UiState.IsFauled -> { ... }
}
}
}
}
private fun setLoading() {
state.value = UiState.IsLoading(true)
}
private fun hideLoading() {
state.value = UiState.IsLoading(false)
}
private fun exception(message: String) {
state.value = UiState.ShowToast(message)
}