fetch data를 어디서 진행하면 좋을까?

기존 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
    )

그렇다면 configuration change가 일어나게 된다면 어떻게 될까? 결과는 유지된다. 동일한 stateFlow에 대해서 configuration change가 일어나기 전의 composable 함수의 uiState와 configuration change가 일어난 후의 composable 함수의 uiState, 즉 두개의 collector가 sateFlow를 collect하게 되는 것이다. 하지만 flow의 onStart는 오직 한 번만 불리기 때문에 그 값이 유지가 되는 것이다.

SharingStarted.WhileSubscribed(5000L)의 역할

위 코드의 역할은 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가 다시 호출되게 된다.