기존 viewModel.init{}
에서 data fetch를 진행하고 있었다. 하지만 멘토님께서 And04A 팀에 남겨주신 코멘트를 바탕으로 다음의 게시글을 읽을 수 있었다. 그리고 관련해서 좋은 영상도 찾아 볼 수 있었다.
The ONLY Correct Way to Load Initial Data In Your Android App?Loading Initial Data in LaunchedEffect vs. ViewModel
크게 많은 사람들이 data initialization를 진행할 때 다음의 두 가지 방식을 사용한다.
1. LaunchedEffect
2. ViewModel.init{}
따라서 등장하게 된 것이 flow
를 사용하는 방식이다.
3. flow를 사용한 data initialization
만약 위와 같이 Ui lifecycle과 viewModel lifecycle 모두에게 영향을 받지 않고 data initialization을 진행하고자 한다면 다음과 같이 flow collection lifecycle에 따라 data initialization을 진행할 수 있다.
private val _issueBoardUiState: MutableStateFlow<UiState<List<IssueResponseVO>>> =
MutableStateFlow(UiState.Init)
val issueBoardUiState = _issueBoardUiState
.onStart {
fetchIssues()
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000L),
UiState.Init
)
onStart
flow lifecycle operator
// Composable screen에서 collect할 때 트리거가 된다.
val uiState by viewModel.issueBoardUiState.collectAsStateWithLifecycle()
stateIn
그렇다면 configuration change
가 일어나게 된다면 어떻게 될까? 결과는 유지된다. 동일한 stateFlow
에 대해서 configuration change가 일어나기 전의 composable 함수의 uiState와 configuration change가 일어난 후의 composable 함수의 uiState, 즉 두개의 collector가 sateFlow를 collect하게 되는 것이다.
하지만 flow의 onStart
는 오직 한 번만 불리기 때문에 그 값이 유지가 되는 것이다.
위 코드의 역할은 flow의 마지막 collector가 사라지고 나서 5초 동안 마지막 마지막 result를 keep and cache하는 것이다. 따라서 flow가 init되고 나서 5초가 지나지 않은 상태에서 configuration change가 발생할 경우, 마지막 collector는 사라지지만 5초동안 마지막 result값이 유지가 되기 때문에 configuration change가 일어나도 onStart가 재호출되지 않는다.
그렇다면 SharingStarted.WhileSubscribed()
를 하면 어떻게 될까? 마지막 collector가 제거되자마자 collection이 멈추기 때문에 result의 keep / cache가 진행되지 않는다.
따라서 configuration change가 일어나면 onStart
가 다시 호출되게 된다.