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

如何构建离线支持的Flow:优先本地数据再拉取远程并持久化

离线优先的Flow实现方案

核心需求

  • 若存在本地结果,优先发射
  • 随后发射远程结果
  • 将远程结果持久化到Room
  • 仅当本地和远程均无结果时,抛出异常

实际场景规则

  • 本地查询无结果(首次调用或出错)时尝试网络请求
  • 网络请求失败则抛出异常,否则发射网络结果
  • 本地查询有结果则发射
  • 拉取远程结果成功则发射,失败则静默处理

初始实现及问题

最初编写的代码如下:

var localResults = emptyList<Movie>()
flow {
    localResults = localSrc.getMovies()
    if (localResults.isNotEmpty()) emit(localResults)
    try {
        val remoteResults = remoteSrc.getMovies()
        localSrc.insert(remoteResults)
        emit(remoteResults)
    } catch (ex: Exception) {
      if (localResults.isEmpty()) throw IllegalStateException()
    }
}

问题:当localSrc.getMovies()抛出异常时,代码会直接中断,无法继续执行后续的远程数据拉取逻辑。

最终解决方案

调整后的代码将本地查询和远程请求的异常处理分离,确保任一环节出错时不阻断另一环节的执行:

suspend fun getMoviesFlow(id: String): Flow<List<Movie>> {
        var fromLocal = emptyList<Movie>()
        return flow {
            try {
                fromLocal = localDataSource.getMovies().map { it.toDomain() }
                if (fromLocal.isNotEmpty()) emit(fromLocal)
            } catch (localEx: Exception) {
                // 捕获本地查询异常,继续执行远程请求逻辑
            }
            try {
                val fromNetwork = fromNetwork(id)
                emit(fromNetwork)
            } catch (remoteEx: Exception) {
                if (fromLocal.isEmpty()) throw IllegalStateException(
                    "fail to fetch movies"
                )
            }
        }
    }

补充说明

  • fromLocal是局部变量,不会在getMoviesFlow(id)的多次调用间共享,也可以将其放入Flow内部定义,结果不受影响。
  • 远程请求成功后,需在fromNetwork方法内部完成将数据持久化到Room的逻辑(原初始代码中的localSrc.insert(remoteResults)操作需迁移至此)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:25:17