如果一切顺利的话,《第二行代码》可能在明天就会开始预售了。预售就是预定的意思,也就是正常开放购买了,然后网店会根据预售的情况来在各地仓库进行备货,通常会在两到三周后正式发货。这次预售首发2000本《第二行代码》,由于需要等待较长时间才能发货,因此会给参加预售的朋友们一次特殊福利,就是预售的2000本《第二行代码》都是我的亲笔签名版,先到先得,售完为至呦。
这次预售主要是和京东合作的,但是京东不承诺会在几点钟将《第二行代码》进行上架,而微信公众号一天又只能推送一次。因此,为了保证我能在预售开始的第一时间立即通知大家,明天早上8点钟就不推送文章了,我会在确认京东完成了上架之后再给大家推送。
当然,这是一切顺利的情况。出版社告诉我,京东也许
会因为
某些原因延迟上架,最晚可能会拖到周四。不过大家放心,只要关注了我的公众号,我一定会在第一时间将消息推送给大家的。
另外,还有很多朋友对于新书的内容也有很多想问的,也请大家放心,我已经写好文章对新书的方方面面进行非常详细的介绍,现在就等京东上架了。
本篇来自
拉丁吴
的投稿,很不错的RxJava入门文章,希望能帮助到有需要的朋友。
拉丁吴
的博客地址:
https://github.com/ladingwu
RxJava
到底是什么?让我们直接跳过官方那种晦涩的追求精确的定义,其实初学RxJava只要把握两点:
观察者模式
和
异步
,就基本可以熟练使用RxJava了。
异步
在这里并不需要做太多的解释,因为在概念和使用上,并没有太多高深的东西。大概就是你脑子里想能到的那些多线程,线程切换这些东西。我会在后面会讲解它的用法。
我们先把
观察者模式
说清楚
“按下开关,台灯灯亮”
在这个事件中,
台灯作为观察者,开关作为被观察者,台灯透过电线来观察开关的状态来并做出相应的处理
观察上图,其实已经很明了了,不过需要指出一下几点(
对于下面理解RxJava很重要
):
-
开关(被观察者)作为事件的产生方(生产“开”和“关”这两个事件),是主动的,是整个开灯事理流程的起点。
-
台灯(观察者)作为事件的处理方(处理“灯亮”和“灯灭”这两个事件),是被动的,是整个开灯事件流程的终点。
-
在起点和终点之间,即事件传递的过程中是可以被加工,过滤,转换,合并等等方式处理的(上图没有体现,后面对会讲到)。
我必须苦口婆心的告诉你:我们总结的这三点对于我们理解RxJava非常重要。因为上述三条分别对应了RxJava中被观察者(Observable),观察者(Observer)和操作符的职能。而
观察者模式又是RxJava程序运行的骨架
。
好了,我假设你已经完全理解了我上面讲述的东西。我们正式进入RxJava!
RxJava也是基于观察者模式来组建自己的程序逻辑的,就是构建
被观察者(Observable),观察者(Observer/Subscriber)
,然后建立二者的订阅关系(就像那根电线,连接起台灯和开关)实现
观察
,在事件传递过程中还可以
对事件做各种处理
。
Tips:
Observer是观察者的接口, Subscriber是实现这个接口的抽象类,因此两个类都可以被当做观察者,由于Subscriber在Observe的基础上做了一些拓展,加入了新的方法,一般会更加倾向于使用Subscriber。
这是最正宗的写法,创建了一个开关类,产生了五个事件,分别是:开,关,开,开,结束。
Observable switcher=Observable.just("On","Off","On","On");
String [] kk={"On","Off","On","On"};
Observable switcher=Observable.from(kk);
偷懒模式是一种简便的写法,实际上也都是
被观察者
把那些信息"On","Off","On","On",包装成onNext("On")这样的事件依次发给
观察者
,当然,它自己补上了onComplete()事件。
以上是最常用到的创建方式,好了,我们就创建了一个开关类。
这也是比较常见的写法,创建了一个台灯类。
之所以说它是非正式写法,是因为Action1是一个单纯的人畜无害的接口,和Observer没有啥关系,只不过它可以当做观察者来使,专门处理onNext 事件,这是一种为了简便偷懒的写法。当然还有Action0,Action2,Action3...,0,1,2,3分别表示call()这个方法能接受几个参数。如果你还不懂,可以暂时跳过。后面我也会尽量使用new Subscriber方式,创建正统的观察者,便于你们理解。
现在已经创建了观察者和被观察者,但是两者还没有联系起来
switcher.subscribe(light);
我猜你看到这里应该有疑问了,为什么是开关订阅了台灯?应该是台灯订阅了开关才对啊。卧槽,到底谁观察谁啊!!
大家冷静,把刀放下,有话慢慢说。
是这样的,台灯观察开关,逻辑是没错的,而且正常来看就应该是light.subscribe(switcher)才对,之所以“开关订阅台灯”,是为了保证
流式API调用风格
啥是
流式API调用风格
?
上面就是一个非常简易的RxJava流式API的调用:同一个调用主体一路调用下来,一气呵成。
由于被观察者产生事件,是事件的起点,那么开头就是用Observable这个主体调用来创建被观察者,产生事件,为了保证流式API调用规则,就直接让Observable作为唯一的调用主体,一路调用下去。
一句话,
背后的真实的逻辑依然是台灯订阅了开关,但是在表面上,我们让开关“假装”订阅了台灯,以便于保持流式API调用风格不变。
好了,现在分解动作都完成了,已经架构了一个基本的RxJava事件处理流程。
我们再来按照观察者模式的运作流程和流式Api的写法复习一遍:
流程图如下:
结合流程图的相应代码实例如下:
嗯,基本上我们就把RxJava的骨架就讲完了,总结一下:
-
创建被观察者,产生事件
-
设置事件传递过程中的过滤,合并,变换等加工操作。
-
订阅一个观察者对象,实现事件最终的处理。
Tips: 当调用订阅操作(即调用Observable.subscribe()方法)的时候,被观察者才真正开始发出事件。
现在开始讲异步操作?别着急,事件的产生起点和处理的终点我们都比较详细的讲解了,接下来我们好好讲讲事件传递过程中发生的那些事儿...
即使你已经看了我上面那段讲解,Rxjava可能还打动不了你,没关系,事件产生的起点和消费的终点其实没那么吸引人,真正有意思的是事件传递过程中的那些鬼斧神工的操作。
由于篇幅的限制,我只讲两三个操作,其他的操作请看我的
RxJava操作的Demo
(
记得在github给我点star或者follow一下,不然我就坐在地上不起来,哼
)
变换
Map操作
比如被观察者产生的事件中只有图片文件路径;,但是在观察者这里只想要bitmap,那么就需要
类型变换
。
你认真看完上面的代码就会觉得,何必在过程中变换类型呢?我直接在事件传递的终点,在观察者中变换就行咯。老实说,你这个想法没毛病,但实际上,上面写的代码是不合理的。
我在代码中也提到,读取文件,创建bitmap可能是一个耗时操作,那么就应该在子线程中执行,主线程应该仅仅做展示。那么线程切换一般就会是比较复杂的事情了。但是在Rxjava中,是非常方便的。
由上面的代码可以看到,使用操作符将事件处理逐步分解,通过线程调度为每一步设置不同的线程环境,完全解决了你线程切换的烦恼。可以说线程调度+操作符,才真正展现了RxJava无与伦比的魅力。
flatmap操作
先提出一个需求,查找一个学校每个班级的每个学生,并打印出来。
如果用老办法:先读出所有班级的数据,循环每个班级。再循环中再读取每个班级中每个学生,然后循环打印出来。
还是得说,这种想法,没毛病,就是嵌套得有点多。
Rxjava说:我不是针对谁...
好了,基本上按照RxJava的骨架搭起来就能完成需求。你说棒不棒??
其实FlatMap是比较难懂的一个操作符,作为初学者其实会用就好,所以我推荐的对于FlatMap的解释是:将每个Observable产生的事件里的信息再包装成新的Observable传递出来,
那么为什么FlatMap可以破除嵌套难题呢?
就是因为FlatMap可以再次包装新的Observable,而每个Observable都可以使用from(T[])方法来创建自己,这个方法接受一个列表,然后将列表中的数据包装成一系列事件。