StateFlow 및 SharedFlow

eunsong·2024년 2월 19일

Android

목록 보기
2/9

https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=en

💡 StateFlow 와 SharedFlow 는 업데이트 상태를 최적으로 내보내주고, 여러 소비자에게 값을 내보내게 할 수 있도록하는 Flow APIs 이다.

StateFlow

StateFlow는 현재 및 새로운 상태 업데이트를 콜렉터에 내보내는 state-holder 관찰 가능한 flow 이다.

현재 상태 값은 value 속성을 통해 읽을 수 있습니다.

상태를 업데이트하고 flow로 보내려면 MutableStateFlow 클래스의 value 속성에 새 값을 할당합니다.

Android 에서 StateFlow는 관찰 가능한 변경 가능 상태를 유지해야하는 클래스에 매우 적합하다.

아래 예제에 따라, StateFlow는 LatestNewsViewModel에서 노출될 수 있으므로 View 는 UI 상태 업데이트를 수신할 수 있고, 본질적으로 화면 상태가 구성 변경 후에도 조성할 수 있다.

class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {

    // Backing property to avoid state updates from other classes
    private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
    // The UI collects from this StateFlow to get its state updates
    val uiState: StateFlow<LatestNewsUiState> = _uiState

    init {
        viewModelScope.launch {
            newsRepository.favoriteLatestNews
                // Update View with the latest favorite news
                // Writes to the value property of MutableStateFlow,
                // adding a new element to the flow and updating all
                // of its collectors
                .collect { favoriteNews ->
                    _uiState.value = LatestNewsUiState.Success(favoriteNews)
                }
        }
    }
}

// Represents different states for the LatestNews screen
sealed class LatestNewsUiState {
    data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
    data class Error(val exception: Throwable): LatestNewsUiState()
}

MutableStateFlow 업데이트를 담당하는 클래스는 생산자이고, StateFlow에서 수집하는 모든 클래스는 소비자입니다. flow builder를 사용하여 구축된 cold flow 와는 달리, StateFlow 는 hot flow 이다. 흐름에서 수집해도 생산자 코드가 트리거되지 않는다. StateFlow는 항상 활성 상태이고, 메모리에 있으며, 가비지 수집 루트에서 이에 대한 다른 참조가 없는 경우, 가비지 수집 대상이 된다.

새 소비자가 flow로부터 수집을 시작하면, 스트림의 마지막 상태와 모든 후속 상태를 받는다. LiveData 처럼 관찰 가능한 클래스로 이 동작을 찾아볼 수 있다.

[In View]

class LatestNewsActivity : AppCompatActivity() {
    private val latestNewsViewModel = // getViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Start a coroutine in the lifecycle scope
        lifecycleScope.launch {
            // repeatOnLifecycle launches the block in a new coroutine every time the
            // lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // Trigger the flow and start listening for values.
                // Note that this happens when lifecycle is STARTED and stops
                // collecting when the lifecycle is STOPPED
                latestNewsViewModel.uiState.collect { uiState ->
                    // New value received
                    when (uiState) {
                        is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
                        is LatestNewsUiState.Error -> showError(uiState.exception)
                    }
                }
            }
        }
    }
}
  • UI 업데이트시 launch 에 직접 수집하면 안된다. repeatOnLifecycle 을 사용하자.
    • androidx.lifecycle:lifecycle-runtime-ktx:2.4.0 library and higher.

StateFlow, Flow 및 LiveData

StateFlow 와 LiveData 는 유사점을 가지고 있다.

  • 둘다 관찰 가능한 data holder class 이다.
  • 앱 아키텍처에 사용될때 비슷한 패턴을 따른다.

다른점

  • StateFlow는 생성자에게 초기 상태를 전달해야 하지만 LiveData는 그렇지 않다.
  • LiveData.observe() 는 뷰가 STOPPED 상태로 전환될때 자동으로 소비자 등록을 취소하는 반면, StateFlow or 다른 flow 에서 수집하는 경우 자동으로 수집이 중지되지 않는다. 동일한 동작을 달성하려면 Lifecycle.repeatOnLifecycle 블록에서 flow를 수집해야한다.

Making cold flow hot using shareIn

StateFlow 는 hot flow 이다. flow가 수집되는 한 다른 참조가 가비지 수집 루트에 존재하는 동안 메모리에 남아 있다. shareIn 연산자를 사용하여 cold flow 를 hot 으로 전환할 수 있다.

SharedFlow

shareIn 함수는 수집하는 모든 소비자에게 값을 내보내는 hot flow 인 SharedFlow 를 반환한다.

profile
A place to study and explore my GitHub projects: github.com/freeskyES

0개의 댓글