如何构建离线支持的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
相关产品推荐
相关产品推荐

