RxJava:合并Observable,远程请求失败用本地数据,mergeDelayError报错问题
解决远程优先、本地 fallback 的 Observable 需求
我明白你的问题所在——mergeDelayError其实并不适合你这个「优先远程请求,失败后用本地数据兜底」的场景,它的设计逻辑和你的需求匹配度不高:
mergeDelayError的作用是合并多个Observable并延迟错误通知:哪怕其中一个Observable出错,它会继续订阅其他Observable发射数据,最后才把所有错误一起抛出来。这就导致哪怕远程请求成功返回了数据,只要本地Observable执行时出现错误,最终你还是会收到错误回调,完全不符合你「远程成功就用远程,只有远程失败才用本地」的核心需求。
正确的实现方式:用onErrorResumeNext操作符
这个操作符的逻辑正好贴合你的需求:当源Observable(远程请求)发生错误时,自动切换到备选Observable(本地数据)继续执行,而且只会在源Observable失败时才会触发备选逻辑。
基础版本代码
fun getCatalogueDetails(id: String): Observable<CatalogueDetails> { // 先尝试远程请求 return getCatalogueDetailsFromRemote(id) // 远程失败时,切换到本地数据 .onErrorResumeNext { throwable -> getCatalogueDetailsFromLocal(id) } }
更严谨的版本(按错误类型过滤)
如果想只在网络相关错误时才用本地兜底(比如解析错误这类非网络问题,直接抛出错误即可),可以在onErrorResumeNext里做判断:
fun getCatalogueDetails(id: String): Observable<CatalogueDetails> { return getCatalogueDetailsFromRemote(id) .onErrorResumeNext { throwable -> // 只处理网络类错误(比如IOException、HttpException等) if (throwable is IOException || throwable is HttpException) { getCatalogueDetailsFromLocal(id) } else { // 其他错误直接抛出,不使用本地数据 Observable.error(throwable) } } }
结合网络判断的优化版本
如果你想保留原代码里的网络判断逻辑(先判断有网才尝试远程),可以这样写:
fun getCatalogueDetails(id: String): Observable<CatalogueDetails> { return if (application.isConnectedToInternet()) { // 有网时先试远程,失败再用本地 getCatalogueDetailsFromRemote(id) .onErrorResumeNext { getCatalogueDetailsFromLocal(id) } } else { // 没网直接用本地 getCatalogueDetailsFromLocal(id) } }
注意:网络判断可能存在滞后性(比如判断时有网,但请求过程中断网),所以加上onErrorResumeNext可以作为双重保障。
内容的提问来源于stack exchange,提问作者Anders Cheow
相关产品推荐
相关产品推荐

