I have the following Composable view and view model. The problem I'm having is that even though isLoading is being updated in the view model, it's not updating the view at all, it's stuck on the LoadingUi.
@Composable
fun MediaDetailsPage(
mediaId: Long?,
viewModel: DetailsViewModel
) {
LaunchedEffect(Unit, block = {
viewModel.fetchDetailsOf(mediaId!!)
})
val isLoading by viewModel.isLoading.collectAsState()
val isError by viewModel.error.collectAsState()
when {
isLoading -> LoadingUi()
isError || viewModel.model == null -> ErrorUi()
else -> MediaDetailsUi(viewModel.model!!)
}
}
class MovieDetailsViewModel(
private val useCase: MovieDetailsUseCase = config.movieDetailsUseCase
) : DetailsViewModel() {
override fun fetchDetailsOf(id: Long, dispatcher: CoroutineDispatcher){
if(model != null) return
fetchFrom({ useCase.getMovieDetailsOf(id) }, dispatcher)
}
}
abstract class DetailsViewModel : ViewModel() {
private val _isLoading = MutableStateFlow(true)
val isLoading: StateFlow<Boolean> = _isLoading
private val _error = MutableStateFlow(false)
val error: StateFlow<Boolean> = _error
var model: MediaDetailsModel? = null
abstract fun fetchDetailsOf(id: Long, dispatcher: CoroutineDispatcher = Dispatchers.IO)
protected fun fetchFrom(
useCaseCall: suspend () -> Either<MediaDetails?, ErrorEntity?>,
dispatcher: CoroutineDispatcher
) {
job( {
_isLoading.value = true
val result = useCaseCall.invoke()
if (result.isSuccess) model = result.body!!.convert()
else _error.value = true
_isLoading.value = false
}, dispatcher)
}
}
The most confusing thing is that I'm doing pretty much identically this elsewhere in the app and that is working perfectly. I was under the impression that a composable view refreshes when a flow variable is updated, or have I got the wrong end of the stick here?