Home > Software engineering >  How not to refresh screen when swipe
How not to refresh screen when swipe

Time:12-30

I am developing an application in which I show a list of potatoes, retrieving the data from Firestore.

I have added a swipe action to refresh the data. With the code that I show below, the data is updating fine, the call is made to Firestore and it is updated showing new values ​​in case they exist, or stopping showing values ​​that no longer exist.

The problem is that when I swipe the potato list screen remains blank, empty, and when the call to Firestore ends, they are shown again. That is, there are a couple of seconds that the screen goes blank.

Is there a possibility that this will not happen? This effect is somewhat ugly

ViewModel:

@HiltViewModel
class PotatoesViewModel @Inject constructor(
    private val getPotatoesDataUseCase: GetPotatoesData
) : ViewModel() {

    private val _state = mutableStateOf(PotatoesState())
    val state: State<PotatoesState> = _state
    private val _isRefreshing = MutableStateFlow(false)
    val isRefreshing: StateFlow<Boolean>
        get() = _isRefreshing.asStateFlow()

    init {
        getPotatoes()
    }

    private fun getPotatoes() {

        getPotatoesDataUseCase().onEach { result ->
            when (result) {
                is Resource.Success -> {
                    _state.value = PotatoesState(potatoes = result.data?.potatoes ?: emptyList())
                }
                is Resource.Error   -> {
                    _state.value = PotatoesState(
                        error = result.message ?: "An unexpected error occurred"
                    )
                }
                is Resource.Loading -> {
                    _state.value = PotatoesState(isLoading = true)
                }
            }
        }.launchIn(viewModelScope)
    }

    fun refresh() {
        viewModelScope.launch {
            _isRefreshing.emit(true)
            getIncidents()
            _isRefreshing.emit(false)
        }
    }
}

Screen:

@Composable
fun PotatoesDataScreen(
    navController: NavController,
    viewModel: PotatoesViewModel = hiltViewModel()
) {
    val state = viewModel.state.value
    val isRefreshing by viewModel.isRefreshing.collectAsState()

    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        stringResource(R.string.app_name),
                        fontWeight = FontWeight.Bold
                    )
                },
                backgroundColor = Primary,
                contentColor = Color.White
            )
        },

        content = {
            Box(modifier = Modifier.fillMaxSize()) {

                SwipeRefresh(
                    state = rememberSwipeRefreshState(isRefreshing),
                    onRefresh = { viewModel.refresh() }
                ) {

                    LazyColumn(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(vertical = 8.dp)
                    ) {
                        items(state.potatoes) { potato ->
                            PotatoCard(
                                potato = potato
                            )
                        }
                    }
                }
            }
        }
    )

}

PotatoState:

data class PotatoesState(
    val isLoading: Boolean = false,
    val potatoes: List<Potato> = emptyList(),
    val error: String = ""
)

CodePudding user response:

When the list screen is blank, this is the time when the Api call is made. When your call is made and response is still not received, this is also when the list is blank. You pass a new Object of PotatoesState to the mutableState every time you:

  1. receive a response,
  2. get an error, (with Potatoes = emptyList())
  3. or state is loading. (with Potatoes = emptyList())

UI is updated according to the MutableState you named _state.

If you want to keep the same data until you get a new response, then you need to update the current state.value: MutableState<PotatoesState> object only when you get a new response (AKA, is Resource.success).

Alternatively, you can implement a Loading Spinner, and show it when you start your Api Request, until isLoading is false.

  • Related