class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
// 다른 클래스의 상태 업데이트를 방지하기 위한 백업 속성
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
// UI는 상태 업데이트를 위해 StateFlow를 수집합니다.
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
// 최신 인기 뉴스로 보기 업데이트
// MutableStateFlow의 value 속성에 기록하여 흐름에 새 요소를 추가하고 모든 수집기를 업데이트합니다.
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
// LatestNews 화면에 다양한 상태를 나타냅니다.
sealed class LatestNewsUiState {
data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
data class Error(val exception: Throwable): LatestNewsUiState()
}
StateFlow는 LatestNewsViewModel에서 출력될 수 있습니다.
따라서, View 상태 업데이트를 수신할 수 있고, 기본적으로 화면 상태가 구성 변경을 유지하도록 합니다.
MutableStateFlow의 업데이트를 담당하는 클래스가 Producer 입니다.
StateFlow를 수집하는 모든 클래스들은 Consumer 입니다.
flow 빌더를 사용하여 구축하는 cold flow 와는 달리, StateFlow는 Flow에서 수집하여도 Producer가 트리거되지 않습니다. > hot flow
StateFlow는 항상 Active 상태이고 메모리에 있습니다.
가비지 컬렉션 루트에서 이에 대한 다른 참조가 없는 경우 가비지 컬렉션 대상이 됩니다.
새로운 Customer가 Flow로부터 수집을 시작할 때, 스트림의 마지막 상태와 후속 상태를 전달받습니다.
View는 다른 Flow와 마찬가지로 StateFlow를 수신합니다.
class LatestNewsActivity : AppCompatActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
...
//수명 주기 범위에서 Coroutine을 시작합니다.
lifecycleScope.launch {
// repeatOnLifecycle 수명 주기가 STARTED 상태에 있을 때마다
// 새 Coroutine에서 블록을 시작하고 STOPPED 일 때 취소합니다.
repeatOnLifecycle(Lifecycle.State.STARTED) {
// Flow를 트리거하고, 값을 수신합니다.
// 수명 주기가 STARTED일 때 발생하고, STOPPED일 때 중지됩니다.
latestNewsViewModel.uiState.collect { uiState ->
// 새로운 값 수신
when (uiState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
}
}
}
}
UI를 업데이트 해야 하는 경우, launch (또는 launchIn) 확장 기능에서 직접 UI에서 Flow를 수집하면 안됩니다.
View가 보이지 않는 경우에도 이벤트를 처리합니다.
이 동작은 앱 충돌로 이루어 질 수도 있습니다.
임의의 flow를 StateFlow를 변환하기 위해서, stateIn 을 사용합니다.
StateFlow, Flow, LIveData
공통점
StateFlow와 LiveData는 서로 유사합니다.
두 관찰가능한 데이터 홀더 클래스
앱 아키텍처에 사용될 때 간단한 패턴을 따릅니다.
다른점
StateFlow는 생성자에 초기 상태를 요청하지만, LiveData는 해당 기능이 없습니다.
LiveData.observe()는 view가 STOPPED 상태가 되면 자동으로 Consumer 등록을 취소합니다.
StateFlow나 다른 flow를 수집해도 자동 중지는 되지 않습니다.
LiveData로 유사한 기능을 구현하려면, Lifecycle.repeatOnLifecycle 블록에서 Flow를 수집합니다.
shareIn을 사용하여 cold flow를 hot으로 만들기
새 Flow를 생성하는 대신 shareIn을 사용하여 수집기 간에 Firestore에서 검색된 데이터를 공유할 수 있습니다.
class NewsRemoteDataSource(...,
private val externalScope: CoroutineScope,
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
...
}.shareIn(
externalScope,
replay = 1,
started = SharingStarted.WhileSubscribed()
)
}
전달해야하는 것들
CoroutineScope : Flow를 공유하는데 사용됩니다.
범위는 공유된 Flow가 필요한 만큼 오래 유지하기 위해 Customer 보다 오래 있어야 합니다.
[TIL-230623] StateFlow 알아보기
안녕하세요
날씨가 많이 더워지고 있네요.. 덥다보니 축 처지게 되는데.. 학습을 게을리 하지말고
하루하루 배우는 시간이 되게 해야겠습니다
오늘은 Android에서 사용되는 StateFlow에 대해 포스팅하려 합니다.
StateFlow에 대해 학습하려면, Flow에 대해 먼저 하시면 이해에 도움이 되실 것 같습니다.
StateFlow란
오늘은 StateFlow에 대해서 알아보았습니다.
'DEV > Android' 카테고리의 다른 글