<aside> <img src="/icons/emoji-sunglasses_orange.svg" alt="/icons/emoji-sunglasses_orange.svg" width="40px" /> StateFlow와 SharedFlow의 대한 정리를 보시려면 클릭하세요!

</aside>

안드로이드에선 어떻게 사용할까?

예시를 하나 들어보자.

서버에서 받아올 데이터가 많다고 가정하고(약 2~3초 동안 데이터를 받아온다고 하자.) 해당 데이터가 다 받아 와야 화면이 보여지는 구조이다.

StateFlow 를 사용하면 위 상태를 크게 3가지의 상태로 나타낼 수 있다.

  1. 로딩 화면 → 데이터가 받아지는 상태
  2. 완료 화면 → 데이터를 다 받아온 상태
  3. 실패 화면 → 서버에러나 request가 올바르지 않은 경우
  4. 예외 화면 → Flow 실행중 예외가 발생했을 경우

그러면 상태는 어떻게 관리할까?

위 상태들을 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)
}