RxJava同时获取数据库与网络数据并缓存功能异常问题排查
问题排查
- 逻辑不符合需求:当前代码中
onErrorResumeNext仅在本地数据库查询抛出异常时才会触发网络请求,既没有实现本地、网络并行拉取数据的效果,也无法覆盖「本地数据库无匹配数据(查询返回空/Null而非执行报错)」的场景 - 缺少数据持久化逻辑:网络请求返回的电影数据没有写入本地数据库的步骤,无法实现后续查询复用本地缓存的效果
正确实现方案
根据你的需求分为两种实现场景:
场景1:并行发起本地+网络请求,优先返回本地缓存,网络返回后更新数据
该场景下由于需要先后返回本地、网络两份数据,需将返回值从Single改为Observable:
fun loadMovie(id: Int): Observable<AboutMovie> = Observable.merge( // 本地查询流 database.getMovie(id = id) .toObservable() .subscribeOn(Schedulers.io()), // 网络请求流,请求成功后自动存入本地库 aboutMovieService.getMovie(movieId = id) .doOnSuccess { networkMovie -> database.insertMovie(networkMovie) // 替换为你的DAO插入方法 } .toObservable() .subscribeOn(Schedulers.io()) ) .observeOn(AndroidSchedulers.mainThread())
场景2:优先查询本地,本地无数据/查询失败才走网络,网络数据自动存库
该场景不需要并行请求,可保留Single返回类型:
fun loadMovie(id: Int): Single<AboutMovie> = database.getMovie(id = id) // 本地无数据/查询出错时走网络请求 .onErrorResumeNext { aboutMovieService.getMovie(movieId = id) .doOnSuccess { networkMovie -> database.insertMovie(networkMovie) } } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
注意事项
- 如果你使用Room实现本地数据库,查询单个不存在的记录默认会抛出
EmptyResultSetException,可被onErrorResumeNext正常捕获;如果你的DAO查询无数据时返回Null,需要额外增加空判断转换为异常触发网络逻辑:
database.getMovie(id = id) .flatMap { movie -> if (movie == null) Single.error(NoSuchElementException("本地无匹配数据")) else Single.just(movie) }
- 上述代码已指定流运行在IO线程,插入数据库的操作不需要额外切换线程。
内容的提问来源于stack exchange,提问作者Svetl9chok
相关产品推荐
相关产品推荐

