I'm trying to implement a refresh button. I want to be able to trigger the api call again when the refresh button is clicked. Kind of confused on what the best practice is. Here is my view model and composable.
View Model:
@HiltViewModel
class CoinListViewModel @Inject constructor(
private val getAllCoinsUseCase: GetListOfCoinsUseCase
): ViewModel() {
private val _state = mutableStateOf(CoinsListState()) // not exposed because mutable
val state: State<CoinsListState> = _state // expose this to composable because immutable
init {
getData()
}
// method to call the use case - put the data in the state object - then display state in the ui
private fun getData(){
getAllCoinsUseCase().onEach { resourceResult ->
when(resourceResult){
is Resource.Loading -> {
_state.value = CoinsListState(isLoading = true)
}
is Resource.Success -> {
_state.value = CoinsListState(coins = resourceResult.data ?: emptyList())
}
is Resource.Error -> {
_state.value = CoinsListState(
error = resourceResult.message ?: "Unexpected Error"
)
}
}
}.launchIn(viewModelScope) // must launch in coroutine scope because using a flow
}
}
Refresh Button:
@Composable
fun RefreshButton(navController: NavController, viewModel: CoinListViewModel) {
// Refresh Button
IconButton(
onClick = {
// Refresh Data
},
modifier = Modifier
.semantics {
contentDescription = "Refresh Button"
testTag = "Refresh Button Test Tag"
},
) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Refresh Icon"
)
}
}
CodePudding user response:
Keep your getData
function private and add another function you can call it onRefreshDataEvent
for example, and on this function call getData
. You may say why I can just call getData
directly, but by this approach we are separating the refresh event from getData
function because you can have another function called getCachedData
and you call it instead or you can have a limit, for example you will not refresh data only one time per minute, so all of this logic will be on onRefreshDataEvent
and your first getData
function stay clean and do it's job.
fun onRefreshDataEvent() {
getData()
}
You can add a time check for example so the user couldn't spam the refresh button, and the refresh could be used only a single time for each minute:
private var lastRefreshTime = 0
fun onRefreshDataEvent() {
val currentTime = System.currentTimeMillis()
if (currentTime - lastRefreshTime > (1000 * 60)) {
getData()
lastRefreshTime = currentTime
}
}
So imagine that the last logic is implemented in getData
function, the code will be messy.