API call using Retrofit2: How can I make API calls all the time, to update the data without reopening the app

69 Views Asked by At

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")
            }
        }
    }
}
2

There are 2 best solutions below

0
BenjyTec On BEST ANSWER

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.

1
m.reiter On

Making API calls "all the time" sounds like you'r DDoSing yourself....

In case you are in control of the server, i suggest using websockets instead. They're a top-pick for applications like messaging apps or small games.

In case you're not in control of the server:

  • expect the server limiting how often you can do calls
  • research the cost per call