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

基于Retrofit2的实时比分APP:无需重启更新赛事数据的实现问询

实时比分应用的数据自动更新方案(基于Retrofit2 + ViewModel)

一、用Retrofit2实现持续API调用(定时轮询方案)

你的ViewModel目前只在初始化时调用一次API,要实现无需重启更新数据,核心是定时重复发起请求,同时结合生命周期管理避免无效请求和内存泄漏。

修改后的ViewModel代码

@HiltViewModel
class LiveMatchesViewModel @Inject constructor(private val liveMatchesRepository: LiveMatchesRepository): ViewModel() {

    private var _liveMatchesState = MutableStateFlow<MatchState>(MatchState.Empty)
    val liveMatchesState: StateFlow<MatchState> =  _liveMatchesState

    init {
        startPeriodicUpdates()
    }

    // 启动定时更新任务
    private fun startPeriodicUpdates() {
        viewModelScope.launch {
            // 每隔30秒发起一次请求(可根据业务调整间隔)
            while (true) {
                fetchLiveMatches()
                delay(30000)
            }
        }
    }

    // 抽取单独的请求方法,复用逻辑
    private suspend fun fetchLiveMatches() {
        _liveMatchesState.value = MatchState.Loading
        try {
            val liveMatchesResponse = liveMatchesRepository.getLiveMatches()
            _liveMatchesState.value = MatchState.Success(liveMatchesResponse)
        } catch (exception: HttpException) {
            _liveMatchesState.value = MatchState.Error("请求失败,请稍后重试")
        } catch (exception: IOException) {
            _liveMatchesState.value = MatchState.Error("无网络连接")
        }
    }
}

额外优化:界面生命周期感知

在Activity/Fragment中观察StateFlow时,用repeatOnLifecycle确保只有界面活跃时才接收更新,避免后台浪费资源:

// 示例:Fragment中观察数据
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.liveMatchesState.collect { state ->
            // 根据状态更新UI(加载中、成功展示数据、错误提示)
        }
    }
}

二、实时比分应用的高效更新方案(低延迟)

定时轮询实现简单但延迟高,适合小流量场景。如果需要更实时的比分更新,推荐用Server-Sent Events(SSE) 或WebSocket,以下是结合Retrofit的SSE实现:

1. 添加SSE依赖

implementation 'com.squareup.okhttp3:okhttp-sse:4.11.0'

2. 定义SSE接口

interface LiveMatchesApi {
    @GET("live/matches/sse")
    fun getLiveMatchesSse(): EventSource
}

3. 仓库层实现SSE监听

class LiveMatchesRepository @Inject constructor(private val api: LiveMatchesApi) {
    fun observeLiveMatches(callback: (Result<List<Match>>) -> Unit): EventSource {
        val listener = object : EventSourceListener() {
            // 接收服务器推送的实时数据
            override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) {
                val matches = Gson().fromJson(data, Array<Match>::class.java).toList()
                callback(Result.success(matches))
            }

            // 处理连接失败
            override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
                callback(Result.failure(t ?: IOException("SSE连接中断")))
            }
        }
        return api.getLiveMatchesSse().newEventSource(listener)
    }
}

4. ViewModel中管理SSE连接

@HiltViewModel
class LiveMatchesViewModel @Inject constructor(private val liveMatchesRepository: LiveMatchesRepository): ViewModel() {

    private var _liveMatchesState = MutableStateFlow<MatchState>(MatchState.Empty)
    val liveMatchesState: StateFlow<MatchState> =  _liveMatchesState
    private var eventSource: EventSource? = null

    init {
        startSseUpdates()
    }

    private fun startSseUpdates() {
        eventSource = liveMatchesRepository.observeLiveMatches { result ->
            viewModelScope.launch {
                result.fold(
                    onSuccess = { matches ->
                        _liveMatchesState.value = MatchState.Success(matches)
                    },
                    onFailure = { throwable ->
                        val errorMsg = if (throwable is IOException) "无网络连接" else "实时更新中断"
                        _liveMatchesState.value = MatchState.Error(errorMsg)
                        // 连接失败后10秒自动重连
                        delay(10000)
                        startSseUpdates()
                    }
                )
            }
        }
    }

    // ViewModel销毁时关闭SSE连接,防止内存泄漏
    override fun onCleared() {
        super.onCleared()
        eventSource?.cancel()
    }
}

关键注意事项

  • 定时轮询的间隔不要过短(推荐15-60秒),避免消耗过多流量和服务器资源。
  • 无论用轮询还是SSE,都要处理错误场景,比如网络断开时展示缓存数据或友好提示。
  • 务必在ViewModel销毁时停止定时任务或关闭SSE连接,防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:38:19