ViewModel repeats init block in Compose

474 views Asked by At

Been trying to figure this out for two days and I'm at my wits end.

I have a ViewModel

data class ExampleUIState(
    val samples: List<Sample> = emptyList(),
    val isLoading: Boolean = false,
    val isError: Boolean = false,
)

class ExampleViewModel(
    private val section: String,
    private val exampleRepository: ExampleRepository = ExampleRepository()
) : ViewModel() {

    private val _uiState = MutableStateFlow(ExampleUIState())
    val uiState: StateFlow<ExampleUIState> = _uiState.asStateFlow()

    init {
        viewModelScope.launch(Dispatchers.IO) {
            _uiState.update { it.copy(isLoading = true) }
            val samplesList = exampleRepository.getSamplesBySection(section)
            if (samplesList.isNotEmpty()) {
                _uiState.update { it.copy(isLoading = false) }
                _uiState.update { it.copy(samples = samplesList) }
            }
        }
    }

}

and a composable

@Composable
fun ExamplesScreen(
    navController: NavController,
    section: String?,
    viewModel: ExampleViewModel = ExampleViewModel(section!!)
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    Column {
        CustomTopAppBar(navController = navController, title = "Ejemplos", showBackIcon = true)

        if (uiState.isLoading) {
            CircularProgressIndicator()
        } else {
            for (sample in uiState.samples) {
                Text(sample.section)
            }
        }
    }
}

When I run the navigate to the composable ExampleScreen, I would like the ViewModel to download network data once and then not refresh. However when I navigate it constantly refreshes, flickering back and forth from CircularProgressIndicator to the list of Text. I cannot for the life of me figure out why, does anybody know?

1

There are 1 answers

0
jojeyh On

The reason it reruns the init block is because I was initializing the ViewModel in the copmosable, so everytime the composable refreshes (which happens a lot) it reinitializes the ViewModel.

I'm using navigation to get to the screen, so I instantiated the ViewModel in my NavGraph and passed it to ExamplesScreen. Works perfectly now.