RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断
来源:互联网 发布:数据运营简历 编辑:程序博客网 时间:2024/06/02 23:51
欢迎转载,转载请标明出处:
http://blog.csdn.net/johnny901114/article/details/52585912
本文出自:【余志强的博客】
RxJava系列文章目录导读:
一、RxJava create操作符的用法和源码分析
二、RxJava map操作符用法详解
三、RxJava flatMap操作符用法详解
四、RxJava concatMap操作符用法详解
五、RxJava onErrorResumeNext操作符实现app与服务器间token机制
六、RxJava retryWhen操作符实现错误重试机制
七、RxJava 使用debounce操作符优化app搜索功能
八、RxJava concat操作处理多数据源
九、RxJava zip操作符在Android中的实际使用场景
十、RxJava switchIfEmpty操作符实现Android检查本地缓存逻辑判断
十一、RxJava defer操作符实现代码支持链式调用
十二、combineLatest操作符的高级使用
十三、RxJava导致Fragment Activity内存泄漏问题
switchIfEmpty(Observable emptyObservable)操作符从字面意思上就很好理解,就是当为空的时候跳转到emptyObservable。
那么如何理解当为空的时候
. 下面将会使用实际案例解释这个switchIfEmpty
的使用方法。
一、业务需求
假如我们的app里有加载文章列表功能,要求加载的逻辑如下:加载文章的的时候,先从本地加载,如果本地存在就是用本地的数据,如果不存在从网络获取。
下面是业务代码:
//从本地数据获取文章列表getArticlesObservable(pageIndex, pageSize, categoryId) //本地不存在,请求api .switchIfEmpty(articleApi.getArticlesByCategoryId(pageIndex + "", pageSize + "", categoryId + "") .compose(this.<RespArticlePaginate>handlerResult()) .flatMap(new Func1<RespArticlePaginate, Observable<RespArticlePaginate>>() { @Override public Observable<RespArticlePaginate> call(RespArticlePaginate respArticlePaginate) { if (respArticlePaginate != null && respArticlePaginate.getList() != null) { try { articleDao.insertOrReplaceInTx(respArticlePaginate.getList()); } catch (Exception e) { e.printStackTrace(); } } return Observable.just(respArticlePaginate); } })) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(createSubscriber(ID_ARTICLE_LIST)))
这里的 createSubscriber
封装了Subscriber对成功、失败的数据处理,然后统一把数据推给上一层,就不用每个地方都写下面相同的模板代码了:
observable.subscribe(new Action1<RespArticlePaginate>() { @Override public void call(RespArticlePaginate respArticlePaginate) { //success data } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { // error data } })
那么createSubscriber
是如何实现的,先看subscribe方法源码 如下:
public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError) { if (onNext == null) { throw new IllegalArgumentException("onNext can not be null"); } if (onError == null) { throw new IllegalArgumentException("onError can not be null"); } Action0 onCompleted = Actions.empty(); return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted)); }
很简单,他是直接new了一个ActionSubscriber,然后把我们以前在代码里写的各个回调(onNext、onError、onComplete)当做参数传递进去。那么我们的createSubscriber
也可以模拟它的实现:
/** * 处理结果(分发结果) 封装 * * @param id 区分业务类型 */ protected <T> ActionSubscriber<T> createSubscriber(final int id) { //因为我们只关心onNext和onError Action0 onCompleted = Actions.empty(); return new ActionSubscriber<T>(new Action1<T>() { @Override public void call(T t) { pushSuccessData(id, t); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { pushThrowable(id, throwable); } }, onCompleted); }
好了,言归正传,回到我们上面提到的需求。根据需求我们来分析下代码:
getArticlesObservable
方法用来从本地获取文章列表,articleApi.getArticlesByCategoryId
方法是用来当本地不存在的时候从网络获取。似乎这些代码可以实现了我们上面提到的需求了。而且很简洁。
实践是检验真理的唯一标准,我们先运行下看看(本地环境是数据库没有文章列表)。
运行后,发现界面并没有展示数据,通过debug返现,代码执行了检测本地缓存的逻辑,且本地找不到符合逻辑的数据,也就是说从本地找到的结果为空。但是没有按照我们预想的是执行网络请求。
先来看看查询本地缓存的代码是是什么样子。
Observable.create(new Observable.OnSubscribe<Object>() { @Override public void call(Subscriber<? super Object> subscriber) { try { List<Article> as = articleDao.queryBuilder() .where(ArticleDao.Properties.CategoryId.eq(categoryId)) .orderDesc(ArticleDao.Properties.Id) .offset((pageIndex - 1) * pageSize) .limit(pageSize).list(); if (as == null || as.isEmpty()) { subscriber.onNext(null); }else{ subscriber.onNext(as); } }catch (Exception e){ subscriber.onError(e); } subscriber.onCompleted(); } });
通过debug发现代码走的逻辑是
if (as == null || as.isEmpty()) { subscriber.onNext(null);}
发送的是空,为什么还是没有走switchIfEmpty里的逻辑呢?肯定是我们用的姿势不对,先看看该该方法的说明:
/** * Returns an Observable that emits the items emitted by the source Observable or the items of an alternate * Observable if the source Observable is empty. * <p/> * <dl> * <dt><b>Scheduler:</b></dt> * <dd>{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.</dd> * </dl> * * @param alternate * the alternate Observable to subscribe to if the source does not emit any items * @return an Observable that emits the items emitted by the source Observable or the items of an * alternate Observable if the source Observable is empty. * @since 1.1.0 */ public final Observable<T> switchIfEmpty(Observable<? extends T> alternate) { return lift(new OperatorSwitchIfEmpty<T>(alternate)); }
重点关注对参数Observable<? extends T> alternate
的解释:
the alternate Observable to subscribe to if the source does not emit any items
意思是如果原来的Observable没有发射任何数据(emit any items),则使用alternate
代替原来的Observable。
好,再看看我们的代码逻辑:
if (as == null || as.isEmpty()) { subscriber.onNext(null);}
这段代码不是没有发射数据,而是发射了个空数据,也就是发射了null,所以这段代码并不是没有发射任何数据,所以为什么不走网络请求的逻辑。
知道原因就好解决了,加上个过滤就可以解决问题了:
.filter(new Func1<RespArticlePaginate, Boolean>() { @Override public Boolean call(RespArticlePaginate respArticlePaginate) { return respArticlePaginate != null; }})
二、总结
1,通过switchIfEmpty可以做到一些逻辑判断,当然实现类型的判断本地缓存的,可以通过concat
结合takeFirst
操作符来实现,具体的可以看我以前的博客文章
2,上面通过Observable.create方式来包装数据查询,不是很优雅。下一篇博客介绍如何封装RxJava,使得我们的代码支持RxJava链式调用。
本文的例子放在github上 https://github.com/chiclaim/android-sample/tree/master/rxjava
- RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断
- &逻辑操作符实现判断的功能
- Android Retrofit RxJava实现缓存
- RxJava操作符(十)自定义操作符
- Android RxJava使用介绍(二) RxJava的操作符
- Android RxJava使用介绍(三) RxJava的操作符
- Android RxJava使用介绍(四) RxJava的操作符
- Android RxJava使用介绍(二) RxJava的操作符
- Android RxJava使用介绍(三) RxJava的操作符
- Android RxJava使用介绍(四) RxJava的操作符
- Android RxJava使用介绍(二) RxJava的操作符
- Android RxJava使用介绍(二) RxJava的操作符
- Android RxJava使用介绍(三) RxJava的操作符
- Android RxJava使用介绍(四) RxJava的操作符
- Android RxJava使用介绍(三) RxJava的操作符
- rxjava实现相关逻辑
- sqlite Android实现本地缓存
- 【Android】Rxjava操作符系列(一)
- 追着嘟嘟学c#系列基础第五篇-----c#字段【蓝鸥出品】
- nginx下基于ThinkPHP框架的网站url重写
- TCP/IP协议三次握手与四次握手流程解析
- 多线程对象传递的坑
- leetcode ----16. 3Sum Closest
- RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断
- Minimum Path Sum
- 91m2中对DB进行了一次封装的DBHelpUtil工具类
- CentOS 7.0 设置iptables防火墙
- HttpClient学习之一
- Mysql中如何设置日期字段默认值为当前日期
- Java中删除文件、删除目录及目录下所有文件
- 作为工程师一定要了解的常用接口大全(收藏版)
- 修改UserAgent iOS