In a Livescores app, how can I make the results of matches updated without reopening the app? Here is my code sample for ViewModel, if anyone can help.
@HiltViewModel
class LiveMatchesViewModel @Inject constructor(private val liveMatchesRepository: LiveMatchesRepository): ViewModel() {
private var _liveMatchesState = MutableStateFlow<MatchState>(MatchState.Empty)
val liveMatchesState: StateFlow<MatchState> = _liveMatchesState
init {
getAllLiveMatches()
}
private fun getAllLiveMatches() {
_liveMatchesState.value = MatchState.Loading
viewModelScope.launch(Dispatchers.IO) {
try {
val liveMatchesResponse = liveMatchesRepository.getLiveMatches()
_liveMatchesState.value = MatchState.Success(liveMatchesResponse)
}
catch (exception: HttpException) {
_liveMatchesState.value = MatchState.Error("Something went wrong")
}
catch (exception: IOException) {
_liveMatchesState.value = MatchState.Error("No internet connection")
}
}
}
}
You can achieve this using a LaunchedEffect
Composable:
LaunchedEffect(Unit) {
while (true) {
liveMatchesViewModel.getAllLiveMatches()
delay(20000) // wait for 20 seconds
}
}
This will re-execute the getAllLiveMatches
function every 20 seconds. You need to make getAllLiveMatches
a public function to make this work.
With this approach, the refreshing will be cancelled when the Composable leaves the composition. You need to judge yourself if this is what you want.
As an alternative, you can execute the same code in the ViewModel in a viewModelScope
. The launch
function returns a Job
that you can cancel when the ViewModel is destroyed using the onCleared
callback.
// ...
private var refreshingJob: Job? = null
init {
getAllLiveMatches()
}
private fun getAllLiveMatches() {
if (refreshingJob != null) return
refreshingJob = viewModelScope.launch(Dispatchers.IO) {
while(true) {
_liveMatchesState.value = MatchState.Loading
try {
val liveMatchesResponse = liveMatchesRepository.getLiveMatches()
_liveMatchesState.value = MatchState.Success(liveMatchesResponse)
} catch (exception: HttpException) {
_liveMatchesState.value = MatchState.Error("Something went wrong")
} catch (exception: IOException) {
_liveMatchesState.value = MatchState.Error("No internet connection")
}
delay(20000) // wait for 20 seconds
}
}
}
// This will be called when the ViewModel is going to be destroyed
override fun onCleared() {
super.onCleared()
refreshingJob?.cancel()
}
This will refresh the data as long as the ViewModel lives, which might be different from the time that the Composable displaying the data is visible.