RxJava之令人尖叫的操作符

嘿,小伙伴们,今天,我继续死磕自己。

写在前面

昨天发了第一篇将RxJava入门篇,由于小伙伴们上一篇反响还不错,让我很受鼓舞。公众号后台有小伙伴给我留言说,希望能在以后的文章里面写一个我自己总结的RxJava实际运用的Demo。我当然答应他了。给自己压力,就是自己在技术栈上前进的动力!不过不是今天这篇文章,预计在本周末会在我的GitHub上面开源一个关于RxJava,上手使用Demo,欢迎持续关注。

子曰:工欲善其事,必先利其器。小伙伴,可以一起带着这样的心境,一起走过这几篇文章的更新吧,先基础打牢,等到我们去实践这门技术的时候,就更加得心应手啦!大家一一起加油,一起升级打怪。

上一篇文章,我介绍了RxJava的一些基础知识,同时也介绍了map()操作符。当然如果你并没有意愿去使用RxJava我一点也不诧异。毕竟才接触了这么一点。看完这篇文章,我相信你肯定想立即在你的项目中使用RxJava了,这篇文章,将介绍许多RxJava的操作符,RxJava的强大性就来自于它所定义的操作符。

万年惯例,先来看一个例子:

准备工作

假设我有这样一个方法:

这个方法根据输入的字符串返回一个网站的url列表

Observable> query(String text);

现在我希望构建一个健壮系统,它可以查询字符串并显示结果。根据上一篇文章的内容,我们可能会写出下面的代码:

query("Hello,world!")

.subscribe(urls ->{

for(String url : urls){

System.out.println(url);

}

});

这种代码当然是不能容忍的,因为上面的代码使我们丧失了变化数据流的能力。一旦我们想要更改每一个URL,只能在Subscriber中来做。我们竟然没有使用如此之酷的map()操作符!

当然,我可以使用map操作符,map中输入的是urls的列表,处理的时候,还是要for each遍历,一样很蛋疼。

万幸,还有Observable.from()方法,它接收一个集合作为输入,然后每次输入一个元素给Subscriber:

Observabke.form("url1","url2","url3")

.subscribe(url -> System.out.println(url));

我们来把这个方法使用到刚才的场景:

query("Hello,world!")

.subscribe(urls ->{

Observable.from(urls)

.subscribe(url -> System.out.println(url));

});

看到这里,也许你会说,虽然去掉了for each循环,但是代码依然看起来很乱。多个嵌套的subscription不仅看起来很丑,代码难以维护,更严重的是它会破坏某些我们现在还没讲到的RxJava的特性。

改进

救世主来临的时刻,程序猿界总是充满着善意的爱,它就是flatMap().

Observable.flatMap()接受一个Observable的输出作为输入。同时输出另外一个Observable。直接看代码:

query("Hello,world!")

.flatMap(new Fun1, Observable>(){

@Override

public Observable call(List urls){

retuen Observable.from(urls);

}

})

.subscribe(url -> System.out.println(url));

这里我贴出了整个函数代码,以方便你了解发生了什么,使用Lambda可以大大简化代码长度:

query("Hello,world!")

.flatMap(urls -> Observable.from(urls))

.subscribe(url -> System.out.println(urs));

flatMap是不是看起来很奇怪?为什么它要返回另外一个Observable呢?理解flatMap的关键点在于,flatMap输出的新的Observable正是我们在Subscriber想要接收的。现在Subscriber不再收到List,而是收到一些单列的字符串,就像Observable.from()的输出一样。

这部分也就是我当初学RxJava的时候最难理解的部分,一旦领悟了,RxJava很对疑问也就有一并解决了。

还可以更好

flatMap()实在不能更赞了,它可以返回任何它想返回的Observable对象。

比如下面的方法:

1、返回网站的标题,如果404了就返回null

2、Observable getTitle(String url);

接着前面的例子,现在我不想打印URL了,而是要打印收到的每个网站的标题。问题来了,我的方法每次只能传入一个URL,并且返回的不是一个String,而是一个输出String的Observable对象。使用flatMap()可以简单的解决这个问题。

query("Hello,world!")

.flatMap(urls - >Observable.from(urls))

.flatMap(new Func1>(){

@Override

public Observable call(String url){

return getTitle(url);

}

})

.subscribe(title -> System.out.println(title));

使用Lambda:

query("Hello, world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(url - > getTitle(url))

.subscribe(title - > System.out.println(title));

是不是感觉很不可思议?我竟然能将多个独立的返回Observable对象的方法组合在一起!帅呆了!不止这些,我还将两个API的调用组合到一个链式调用中了。我们可以将任意多个API调用链接起来。大家应该都知道同步所有API调用,然后将所有API调用的回调结果组合成需要展示的数据,这是一件多么蛋疼的事情。在这里,我们成功的避免了callback (多层嵌套的回调,导致代码难以阅读维护)。现在所有的逻辑都包装成了这种简单的响应式调用。

丰富的操作符

目前为止,我们已经接触了两个操作符,RxJava中还有更多的操作符,那么,我们如何使用其他操作符来改进我们的代码呢?

getTitle()返回null如果url 不存在。我们不想输出 “null” ,那么我们可以从返回的title列表中过滤掉null 值!

query("Hello,world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(ur; - > getTitle(url))

.filter(title - > title !=null)

.subscribe(title - > System.out.println(title));

filter()输出和输入相同的元素,并且会过滤掉那些不满足检查条件的。

如果我们只想要最多5个结果:

query("Hello,world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(url - > getTitle(url))

.filter(title - > title! =null)

.take(5)

.subscribe(title - > System.out.println(title));

take()输出最多指定数量的结果。

如果我们在打印之前,把每个标题保存到磁盘:

query("Hello,world!")

.flatMap(urls - > Observable.form(urls))

.flatMap(url - > getTitle(url))

.flatMap(title - > title !=null)

.take(5)

.doOnNext(title - > saveTitle(title))

.subscribe(title - > System.out.println(title));

doOnNext()允许我们在每次输出一个元素之前做一些额外的事情,比如这里的保存标题。小伙伴们,看到这里操作数据是多么简单了吗?你可以添加任意多的操作,并且不会搞乱你的代码。

RxJava包含了大量的操作符。操作符的数量是有点吓人,但是很值得你挨个去看一下,这样你可以知道哪些操作符可以使用。弄懂这些操作符可能会花一些时间,但是一旦弄懂了,你就完全掌握了RxJava的威力了。

总结

好吧,如果你是一个怀疑主义者,并且很难被说服,那么为什么要关心这些操作符呢?

因为操作符可以对数据流做任何操作。

将一系列的操作符链接起来就可以完成复杂的逻辑。代码被分解成一系列可以组合的片段。这就是响应式函数编程的魅力所在。用的越多,将会越多的改变你的编程思维。

另外,RxJava也使我们处理数据的方式变得简单。再最后一个例子里,我们调用了两个API,对API返回的数据进行了处理,然后保存到磁盘。但是我们的Subscriber并不知道这些,它只是认为自己在接收一个Observable对象。良好的封装性也带来了编码的便利!

嘿,小伙伴们,看到这里是不是觉得对RxJava相见恨晚呢?我现在就有这种感觉!

在我的公众号的下一篇文章里,我会继续介绍RxJava的另外一些很酷的特性,比如错误的处理和并发,不过,这些特性不会直接用来处理数据。

更多内容请关注我的个人微信公众号:前端开发技术栈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容