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

双Fragment赛事数据展示异常:已结束赛事无法同步至Recent Races列表

解决方案:同步已结束赛事到Recent Races列表

看起来你的核心问题是数据更新时,Recent Races列表没有触发重新过滤和刷新,而Upcoming Races能正常工作,大概率是数据流的触发逻辑或订阅方式出了问题。以下是分步排查和修复方案:


1. 先优化低效且有风险的日期过滤逻辑

你当前的过滤代码存在重复创建格式化器、冗余日期转换的问题,而且SimpleDateFormat不是线程安全的,可能导致解析异常。先把这部分重构得更简洁可靠:

// 把日期格式化器提到方法外,DateTimeFormatter是线程安全的,可复用
private val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")

private fun getDetails() {
    getRaceDetailsUseCase().onEach { result ->
        when (result) {
            is Resource.Success -> {
                val currentDate = LocalDate.now() // 直接获取当前本地日期,跳过字符串转换
                val filteredRecentRaces = result.data.filter { race ->
                    // 用runCatching处理日期解析失败的情况,避免崩溃
                    runCatching {
                        val raceDate = LocalDate.parse(race.date, dateFormatter)
                        currentDate >= raceDate // 筛选已结束(含当天)的赛事
                    }.getOrDefault(false)
                }
                _state1.value = Resource.Success(filteredRecentRaces)
            }
            is Resource.Error -> {
                _state1.value = Resource.Error("Failed to load recent races")
            }
            is Resource.Loading -> {
                _state1.value = Resource.Loading(true)
            }
        }
    }.launchIn(viewModelScope)
}

2. 确保数据流能同步更新所有订阅者

你的RaceDetailsUseCase返回的是冷流(每次调用invoke()才会发起一次API请求),这意味着:当API数据更新时,Recent Races的ViewModel不会自动收到新数据,除非你主动重新调用getDetails()。而Upcoming Races可能因为某种逻辑(比如定时刷新或用户交互)重新触发了请求,所以能正常更新。

要解决这个问题,需要把Repository的数据流改成热流(比如StateFlow),让所有订阅者(Recent和Upcoming的ViewModel)能实时收到数据更新:

第一步:修改Repository,维护一个可更新的StateFlow

class RaceResultsRepository {
    // 用MutableStateFlow维护全局赛事数据状态
    private val _raceData = MutableStateFlow<Resource<List<RaceDomain>>>(Resource.Loading(true))
    val raceData: StateFlow<Resource<List<RaceDomain>>> = _raceData

    // 主动刷新数据的方法,调用API后更新StateFlow
    suspend fun refreshRaceResults() {
        try {
            _raceData.value = Resource.Loading(true)
            val newRaceData = // 调用你的API接口获取最新赛事数据
            _raceData.value = Resource.Success(newRaceData)
        } catch (e: HttpException) {
            _raceData.value = Resource.Error("Network error occurred")
        } catch (e: IOException) {
            _raceData.value = Resource.Error("Failed to connect to server")
        }
    }

    // 对外提供订阅数据流的方法
    fun getRaceResultsFlow(): StateFlow<Resource<List<RaceDomain>>> {
        // 如果还没加载过数据,自动触发一次刷新
        if (_raceData.value is Resource.Loading) {
            // 注意:这里需要用CoroutineScope,可在Repository构造时注入或用GlobalScope(不推荐,最好用DI提供的scope)
            CoroutineScope(Dispatchers.IO).launch { refreshRaceResults() }
        }
        return raceData
    }
}

第二步:修改UseCase,返回热流

class RaceDetailsUseCase @Inject constructor(
    private val repository: RaceResultsRepository
) {
    operator fun invoke(): StateFlow<Resource<List<RaceDomain>>> {
        // 直接返回Repository的StateFlow,不再每次创建新的flow
        return repository.getRaceResultsFlow()
    }
}

3. 确保Fragment正确观察ViewModel状态

最后检查Recent Races的Fragment是否用viewLifecycleOwner观察状态,避免内存泄漏或数据不更新:

// 在RecentRacesFragment的onViewCreated方法中
recentRacesViewModel.state1.observe(viewLifecycleOwner) { resource ->
    when (resource) {
        is Resource.Success -> {
            // 更新RecyclerView适配器数据
            yourAdapter.submitList(resource.data)
        }
        is Resource.Error -> {
            // 显示错误提示,比如Toast或空状态布局
            Toast.makeText(requireContext(), resource.message, Toast.LENGTH_SHORT).show()
        }
        is Resource.Loading -> {
            // 显示加载动画或骨架屏
        }
    }
}

额外验证点

  • 确认Upcoming Races的过滤条件是currentDate < raceDate,和Recent的currentDate >= raceDate形成互补,确保所有赛事都会被分到其中一个列表(排除日期解析失败的情况)。
  • 当API数据更新时,调用repository.refreshRaceResults(),此时两个ViewModel都会收到新数据,自动重新过滤并更新各自的列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:02:42