StateFlow에 대해 알아보자‼️

GongBaek·2024년 5월 9일
1
post-thumbnail

🎉 StateFlow


StateFlow란?

StateFlow는 코틀린에서 제공하는 Flow API의 일부입니다‼️
어떤 상태의 현재 값을 저장하고 있으며, 이 상태 값이 변경될 때마다 구독하고 있는 구성요소들에게 새로운 상태를 알릴 수 있는 기능을 가진 데이터 흐름🐳입니다.

간단히 말해, StateFlow는 특정 상태의 최신 값을 관찰하고, 이 값이 변경될 때마다 자동으로 업데이트를 알려주는 역할을 합니다. 이를 통해 코루틴과 함께 상태 관리를 보다 쉽고 효율적으로 할 수 있게 돕습니다.

LiveData랑 뭐가 다른데?

  • 초기 상태: StateFlow는 생성 시 초기 상태 값을 제공해야 하지만, LiveData는 초기 상태 값을 설정하지 않아도 됩니다.
  • 생명주기 인식: LiveData는 안드로이드의 생명주기를 인식하고, 뷰가 STOPPED 상태가 되면 자동으로 관찰을 중지합니다. 반면, StateFlow는 생명주기 인식이 내장되어 있지 않습니다‼️ 따라서 인식이 필요하다면 Lifecycle.repeatOnLifecycle을 사용하여 비슷한 기능을 구현해야 합니다.
  • 불변성: StateFlow는 Hot Stream의 일종으로 불변성을 보장하며, 상태 값이 변경될 때마다 새로운 객체를 생성합니다. LiveData는 내부 상태를 변경할 수 있어, 예기치 않은 변경이 발생할 수 있습니다.
  • 플랫폼 의존성: LiveData는 안드로이드 플랫폼에 종속적이라 UI가 없는 곳에서 사용하기 어렵습니다. 반면, StateFlow는 순수 Kotlin 기반으로 동작하기 때문에 안드로이드 플랫폼에 독립적이며, UI가 없는 환경에서도 사용할 수 있습니다.

LiveData는 UI와 긴밀한 데이터를, StateFlow는 보다 유연하게 사용해야 하는 데이터를 다룬다. 각각 상황에 맞게 쓰면 좋을 것 같다.

어떻게 사용하는데?

아래와 같이 viewModel을 만들고 dummyUseCase를 주입해서 사용하고 있음을 볼 수 있습니다.
onStart에선 로딩, catch에선 오류, collectLatest에서는 성공을 보내주고 있죠?!

사용 자체는 굉장히 쉽습니다. ☺️

@HiltViewModel
class MainViewModel @Inject constructor(
        private val dummyUseCase: DummyUseCase
) : ViewModel() {

// 초기값도 야무지게 지정하는 모습을 볼 수 있죠?
  private val _dummyUIState = MutableStateFlow<UIState<Dummy>>(UIState.Empty)
  val dummyUIState: StateFlow<UIState<Dummy>> = _dummyUIState

  private fun getDummy() {
  // viewModelScope를 따라감
    viewModelScope.launch {
      dummyUseCase()
      		// 시작시
              .onStart { _dummyUIState.update { UIState.Loading } }
      		// 오류시
              .catch { e -> _dummyUIState.update { UIState.Error(e) } }
      		// 성공시
              .collectLatest { value -> _dummyUIState.update { UIState.Success(value) } }
    }
  }
}

이렇게 만든 viewModel을 Activity에서 사용하는 과정을 볼까요?
다음과 같이 사용하면 됩니다 😎

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val mainViewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycleScope.launchWhenStarted {
            mainViewModel.dummyUIState.collectLatest { state ->
                when (state) {
                    is UIState.Loading -> {
                        Snackbar.make(binding.root, "로딩 중...", Snackbar.LENGTH_SHORT).show()
                    }
                    is UIState.Success -> {
                        Snackbar.make(binding.root, "성공 >_<", Snackbar.LENGTH_SHORT).show()
                    }
                    is UIState.Error -> {
                        Snackbar.make(binding.root, "오류 -_-", Snackbar.LENGTH_SHORT).show()
                    }
                }
            }
        }
    }

위 코드에서 상태에 따라 스낵바를 띄워주는 모습을 볼 수 있습니다 ‼️
참 쉽죠? 😅

SharedFlow는 뭐가 또 다른건데?

  • 값 보유: SharedFlow는 초기값을 갖고 있지 않고, 값의 보유 여부는 replay 매개변수에 의해 결정됩니다. 즉, collect될 때 몇 개의 이전 데이터를 전달받을지 replay를 통해 정의할 수 있습니다.
  • Hot Stream: SharedFlow는 StateFlow와 마찬가지로 Hot Stream 방식입니다.

SharedFlow는 이벤트 전달이나 데이터 스트림의 다양한 처리에 더 적합하며, 특히 값을 보유하지 않는 이벤트 전송에 유리하다고 볼 수 있습니다 ‼️

글을 마치며...

항상 중요한 이야기지만 코딩에 정답은 없습니다 🤭
상황에 맞게 적절한 방식을 사용해 상태관리를 한다면, 여러분도 상태관리의 신이 될 수 있어요~~ 👍

profile
Junior Android Developer

0개의 댓글