RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断
欢迎转载,转载请标明出处:
http://blog.csdn.net/johnny901114/article/details/52585912
本文出自:【余志强的博客】
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链式调用。
RxJava(十)switchIfEmpty操作符实现Android检查本地缓存逻辑判断的更多相关文章
- Android ImageLoader 本地缓存
Android ImageLoader 本地缓存 本地缓存 ...
- Android -- ImageLoader本地缓存
传送门 <Android -- ImageLoader简析> http://www.cnblogs.com/yydcdut/p/4008097.html 本地缓存 在缓存文件时对文件名称 ...
- Android 清除本地缓存
主要功能:清除内.外缓存,清除数据库,清除Sharepreference,清除files和清除自定义目录 public class DataCleanManager { //清除本应用内部缓存(/da ...
- 深入浅出RxJava(二:操作符)
看完这篇blog,我相信你肯定想立即在你的项目中使用RxJava了,这篇blog将介绍许多RxJava中的操作符,RxJava的强大性就来自于它所定义的操作符. 首先先看一个例子: 准备工作 假设我有 ...
- RxJava学习笔记(操作符)
前言 上一篇文章介绍了RxJava的基础知识和简单实现,篇幅已经比较多了,所以把操作符(Operators)相关的内容放在这一篇.有了上一篇文章的基础,相信会比较容易理解操作符相关的内容了. 操作符( ...
- Android清除本地数据缓存代码案例
Android清除本地数据缓存代码案例 直接上代码: /* * 文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除shar ...
- Android远程图片获取和本地缓存
对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对 应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用 ...
- spring boot / cloud (十八) 使用docker快速搭建本地环境
spring boot / cloud (十八) 使用docker快速搭建本地环境 在平时的开发中工作中,环境的搭建其实一直都是一个很麻烦的事情 特别是现在,系统越来越复杂,所需要连接的一些中间件也越 ...
- Android中本地广播的实现
其实Android的本地广播并没有什么好讲的,他就是用了一个localbroadcastmanager类来sendbroadcast,以及注册和注销广播,没有什么特点,其中实例该类的时候用了getin ...
随机推荐
- linux系统命令学习系列8-文件相关操作touch,rm,mv,cat,head,tail命令
上节内容: 系统和目录管理 Pwd命令 .和..目录 相对路径和绝对路径 作业:进入opt路径,分别使用相对路径方法和绝对路径方法进入到其实任意一个子目录 cd /opt 相对路径 cd rh 绝对路 ...
- Lintcode388 Permutation Sequence solution 题解
[题目描述] Given n and k, return the k-th permutation sequence. Notice:n will be between 1 and 9 inclusi ...
- Java IO(五)==>>重点
打印流:PrintStream与PrintWriter PrintStream 该类的定义如下: public class PrintStream extends FilterOutputStream ...
- 1086: [SCOI2005]王室联邦
1086: [SCOI2005]王室联邦 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1554 Solved: ...
- TopCoder SRM 558 Div 1 - Problem 1000 SurroundingGame
传送门:https://284914869.github.io/AEoj/558.html 题目简述 一个人在一个n * m棋盘上玩游戏,想要占领一个格子有两个方法: 在这个格子放一个棋子. 这个 ...
- hdu 5437Alisha’s Party(优先队列)
题意:邀请k个朋友,每个朋友带有礼物价值不一,m次开门,每次开门让一定人数p(如果门外人数少于p,全都进去)进来,当所有人到时会再开一次,每次都是礼物价值高的人先进. /*小伙伴最开始gg了,结果发现 ...
- hdu 5468(莫比乌斯+搜索)
hdu 5468 Puzzled Elena /*快速通道*/ Sample Input 5 1 2 1 3 2 4 2 5 6 2 3 4 5 Sample Output Case #1: ...
- Codeforces Round #430 D. Vitya and Strange Lesson
Today at the lesson Vitya learned a very interesting function - mex. Mex of a sequence of numbers is ...
- bzoj3295[Cqoi2011]动态逆序对 树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5987 Solved: 2080[Submit][Sta ...
- widows下的进程与服务
进程: 当程序卡死的时候,我们可以直接通过任务管理器来关闭进程. 服务: 在这个界面,我们可以选择启动或者关闭相关服务,还可以选择服务是否自动启动. 以关闭MySQL自启动服务为例:https://j ...