【问题标题】:How not to refresh screen when swipe滑动时如何不刷新屏幕
【发布时间】:2021-12-29 14:51:10
【问题描述】:

我正在开发一个应用程序,其中显示土豆列表,从 Firestore 检索数据。

我添加了一个滑动动作来刷新数据。使用我在下面显示的代码,数据更新正常,调用 Firestore 并更新显示新值(以防它们存在),或停止显示不再存在的值。

问题是当我滑动土豆列表屏幕时仍然是空白的,当对 Firestore 的调用结束时,它们会再次显示。也就是说,屏幕会在几秒钟内变为空白。

有没有可能这不会发生?这个效果有点难看

视图模型:

@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)
        }
    }
}

屏幕:

@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
                            )
                        }
                    }
                }
            }
        }
    )

}

土豆状态:

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

【问题讨论】:

  • 你的PotatoesState有什么代码?
  • 抱歉,我编辑了问题。

标签: android firebase kotlin google-cloud-firestore android-jetpack-compose


【解决方案1】:

当列表屏幕为空白时,这是进行 Api 调用的时间。 当您拨打电话但仍未收到回复时,这也是列表为空白的情况。 每次您将PotatoesState 的新对象传递给mutableState

  1. 收到回复,
  2. 得到一个错误,(Potatoes = emptyList()
  3. 或状态正在加载。 (Potatoes = emptyList()

根据您命名为_stateMutableState 更新UI。

如果您想在收到新响应之前保留相同的数据,那么您需要仅在收到新响应时更新当前的 state.value: MutableState&lt;PotatoesState&gt; 对象(AKA,is Resource.success)。

或者,您可以实现一个 Loading Spinner,并在您启动 Api 请求时显示它,直到 isLoadingfalse

编辑:添加建议代码。

那么我将如何声明 PotatoesState 类:

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

这就是我要在回调函数中写的内容:

when (result) {
    is Resource.Success -> {
        if (result.data != null) {
            _state.value = mutableStateOf().apply {
                addAll(_state.value.apply { it ->
                    it.potatoes = result.data!!.potatoes
                    it.isLoading = false
                    it.error = ""
                })
            }
        }
    }
    is Resource.Error   -> {
        _state.value = mutableStateOf().apply {
            addAll(_state.value.apply { it ->
                it.error =
                    result.message ?:
                        "An unexpected error occurred"
                it.isLoading = false
            })
        }
    }
    is Resource.Loading -> {
        _state.value = mutableStateOf().apply {
            addAll(_state.value.apply { it ->
                it.isLoading = true
            })
        }
    }
}

【讨论】:

  • 哦,它真的如你所说,我评论了错误和 isLoading 案例但是如果我想检测错误或 isLoading 怎么办?
  • 您可能需要使用没有data 关键字的class。这将使您能够使用var 而不是val 定义类属性。然后您只需为PotatoesState 对象的属性分配新值,而无需创建新实例。这将使您有机会将当前数据保留在同一个对象中,直到您有其他数据可以替换它。
  • 好吧,这不起作用...我删除了PotatoesState 中的data 关键字,以及success case 中的PotatoesViewModel,我输入:_state.value.potatoes = result.data?.potatoes ?: emptyList() 但现在列表为空总是,在屏幕上什么也不显示。
  • @Paul9999 永远不要传递emptyList(),除非你想故意显示一个空白列表!检查if (result.data != null &amp;&amp; result.data.potatoes != null),然后仅在数据不为空时才传递数据。另外,尝试使用_state.value = mutableListOf().apply{ addAll(_state.value.apply { result.data!!.potatoes })}
  • 我已编辑我的答案以包含我将使用的代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-25
  • 1970-01-01
  • 2015-04-06
  • 2013-05-16
相关资源
最近更新 更多