You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose Horizontal Pager列表状态保存及数据更新问题排查

问题原因
  1. 你在ViewModel中通过getQuestions监听了数据库的全量查询Flow,只要调用updateKnowAnswer修改了数据库中题目的knowAnswer字段,distinctUntilChanged检测到数据集变更就会推送新的QueryState.Success状态到UI层。
  2. 你当前在UI层每次收到新的Success状态都会重新执行shuffled()打乱列表,自然会生成全新的题目序列,HorizontalPager的状态也会被同步重置。
解决方案

方案一:在ViewModel中缓存打乱后的列表(更推荐)

将筛选、打乱逻辑放到ViewModel侧,仅在首次加载、用户主动切换筛选条件时重新生成打乱序列,数据库更新时仅修改列表对应条目的字段,不改变整体顺序。
修改ViewModel代码:

// 缓存当前使用的筛选条件
private var currentFilter: String = "all"
// 缓存已打乱的题目列表
private val _cachedShuffledQuestions = MutableStateFlow<List<CertQuestions>>(emptyList())
val cachedShuffledQuestions = _cachedShuffledQuestions.asStateFlow()

fun getQuestions() = viewModelScope.launch {
    try {
        certsRepository.getAllQuestions().distinctUntilChanged().collect(){ dbResult->
            if(dbResult.isEmpty()){
                _quState.value = QueryState.Empty
                _cachedShuffledQuestions.value = emptyList()
            }else {
                _quState.value = QueryState.Success(dbResult)
                // 仅缓存为空或筛选条件变更时重新生成打乱序列
                if (_cachedShuffledQuestions.value.isEmpty()) {
                    refreshShuffledList(dbResult)
                } else {
                    // 数据库更新时仅更新对应条目字段,保留原有顺序
                    val updatedList = _cachedShuffledQuestions.value.map { cachedQuestion ->
                        dbResult.find { it.question_id == cachedQuestion.question_id } ?: cachedQuestion
                    }
                    _cachedShuffledQuestions.value = updatedList
                }
            }
        }
    }catch (e: Exception){
        _quState.value = QueryState.Error(exception = e)
    }
}

// 单独抽出生成打乱列表的逻辑,用户切换筛选条件时可主动调用
fun refreshShuffledList(rawList: List<CertQuestions>? = null) {
    val sourceList = rawList ?: (_quState.value as? QueryState.Success)?.queries ?: return
    _cachedShuffledQuestions.value = when (currentFilter) {
        "pass" -> sourceList.filter { it.knowAnswer }.shuffled()
        "new" -> sourceList.filter { !it.knowAnswer }.shuffled()
        "random25" -> sourceList.shuffled().take(25)
        "random65" -> sourceList.shuffled().take(65)
        else -> sourceList.shuffled()
    }
}

// 切换筛选条件时调用该方法
fun updateFilter(newFilter: String) {
    currentFilter = newFilter
    refreshShuffledList()
}

UI层直接收集cachedShuffledQuestions作为HorizontalPager的数据源即可,不需要再在UI层做打乱操作。

方案二:UI层缓存打乱后的列表

如果筛选逻辑不需要和ViewModel绑定,也可以在UI层用rememberSaveable缓存打乱后的列表,仅筛选条件变化时重新生成:

// 缓存当前筛选条件
val filter by rememberSaveable { mutableStateOf("all") }
// 缓存打乱后的题目列表,filter变化时自动重置
var lstQuestions by rememberSaveable(filter) { mutableStateOf<List<CertQuestions>>(emptyList()) }

when (val result = mainDataViewModel.quState.collectAsState().value) {
    is QueryState.Error -> {
        Log.d("Error", "Error Occured")
    }
    is QueryState.Success -> {
        if (lstQuestions.isEmpty()) {
            // 仅列表为空时生成打乱序列
            lstQuestions = when (filter) {
                "pass" -> result.queries.filter { it.knowAnswer }.shuffled()
                "new" -> result.queries.filter { !it.knowAnswer }.shuffled()
                "random25" -> result.queries.shuffled().take(25)
                "random65" -> result.queries.shuffled().take(65)
                else -> result.queries.shuffled()
            }
        } else {
            // 数据库更新时仅更新对应条目字段,保留顺序
            lstQuestions = lstQuestions.map { cachedQ ->
                result.queries.find { it.question_id == cachedQ.question_id } ?: cachedQ
            }
        }
    }
}
关于更新方法的说明

你当前的updateKnowAnswer调用逻辑没有问题,只是数据库更新后触发了上游Flow的回调,导致UI层重新打乱列表才出现的问题,修改完上述缓存逻辑后即可正常运行。

内容的提问来源于stack exchange,提问作者srituts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 07:54:05