Rx初探

1.什么是Rx

是一种基于事件驱动的,异步数据流的编程模型;
英文全名是Reactive Extension,2012年11月开源。Rx并不是一种编程接口,而是一种编程思想,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流
用中文翻译就是响应式编程(通俗的讲:反应式编程),就是因为我们得“响应”这些事件而得以命名。

例如,你订了一份外卖,在你等待外卖的时候继续工作,当外卖小哥给你打电话叫你去取餐的时候,你会立即响应。这是最简单的执行任务的反应(响应)形式。

int x=111;
int y=x+111;
System.out.print(“y=”+y) // b=222
x=1111;
System.out.print(“y=”+y) // b=222

int x=111;
int y <= x+111; // <= 符号只是表示x和y之间关系的操作符
System.out.print(“y=”+y) // y=222
x=1111;
System.out.print(“y=”+y) // b=1222

这种编程的思想,是企图构建某种关系,而不是执行某种赋值语句。编写代码基于对变化的反应。
这种灵感来源于生活,也就是我们如何采取行动和与他人沟通。
其实在项目开发中过程中,也总是存在着各种业务关系,需要不断处理一系列的业务逻辑相互作用。
然而,我们的编程语言并没有表示关系的构建方式。
因此Rx应运而生。
首先要熟悉三个概念:

  1. 事件
  2. 异步
  3. 数据流

何为事件?代码的角度来讲就是一段业务逻辑。通俗的讲,例如,每次顶一个外卖都是一个“事件”。如果你看看订单列表,你会发现其实是一个随着时间的推移(一系列的事件)发生的一系列的“事件”。

异步编程,我们可能只能在一个线程中顺序调用这三个相对耗时较多的业务,如图,然后再去做页面跳转,如果顺序执行不仅没有忠实反映业务本来的关系,而且会让你的程序“反应”更慢。区分出无关

异步操作.png

数据流只是事物之间沟通的桥梁。每一个业务完成后,都会有一条数据(一个事件)流向下游,下游的业务收到这条数据(这个事件),才会开始自己的工作。联系起有关

异步和数据流都是为了正确的构建事物的关系而存在的。通过 异步 和 数据流 来构建事物关系的编程模型。只不过,异步是为了区分出无关的事物,而数据流(事件流)是为了联系起有关的事物。

2.观察者模式(触发联动)银行卡

即当一个对象发生变化时,依赖它的所有对象都会被通知并且会自动更新。

观察者模式.png

1.生产者在没有更多数据可用时能够发出信号通知:onCompleted()事件。
2.生产者在发生错误时能够发出信号通知:onError()事件。
3.RxJava Observables 能够组合而不是嵌套,从而避免开发者陷入回调地狱。

3.有什么优势

在业务层面实现代码逻辑分离,方便后期维护和拓展
极大提高程序响应速度,充分发掘CPU的能力
帮助开发者提高代码的抽象能力和充分理解业务逻辑
Rx丰富的操作符会帮助我们极大的简化代码逻辑

一句话简单描述:避免“回调地狱”的问题,解耦代码。
代码运行的顺序不是代码行的顺序

    void 生产汽车(){
            汽车 phone = 汽车模版.build("car");
            装发动机(car){
                onSuccess(){ 
                     装方向盘(car){
                              onSuccess() { 
                                    装座椅(car) { 
                                           onSuccess() { 
                                                    continue(); .... 
                                                              }
                            onFailure() {
                                 handleError(); ... 
                                              }
                        }
                }
                    onFailure()
                    { print(msg); }
                }
                } onFailure(msg)
                { print(msg);
                }
            }
        }
汽车生成流水线.from(汽车毛胚序列[]) //先把毛胚按序放到生产线上面 
 .map(装发动机())
 .map(装方向盘())
 .map(装座椅()) 
 .map(装导航()) 
 .subscribe(出厂); //生产线的尾端,将好的产品打包

4.应用在哪

应用.png
  1. 在后端系统中给你一种新的学习扩展和并发的方式,而这不需要更换开发语言;
  2. 你克服Android平台局限性从而创建一个基于事件驱动的,响应式的,流畅体验的Android应用;rxandroid 中viewobservable,widgetObservable,lifecycleObservable;rxBinding
    可能是东半球最全的RxJava使用场景小结
    5.操作符
    四大类:

1.创建 create from(迭代) just(整串) empty never error publishSubject BehaviorSubject ReplaySubject AsyncSubject

2.过滤 就像一个纱窗 过滤掉不要的 留下想要的 filter(from 组合 过滤空数据)range repeat interval timer take skip frist last elementAt distinct distinctUtilChanged throttleFirst(指定时间的第一个) Timeout

3.变换 就像一个加工厂 对原料进行加工 生成新的 map flamap (合并 允许交叉,重要是记住每一个发生错误的情况,flatmap会触发自己的onerror map() 是一对一的转化,而flatmap是一对多的转化)
concatMap (不合并 ,连续在一起 不会交叉) flatmapIterable 两两结对 switchMap停止前边的 scan将返回结果带回继续发射 groupBy cast buffer window

4.组合 merge (多输入 单输出 如果是同步的不会交叉 异步会交叉 mergeDelayError 发生错误所有完成后发送onerror)
zip 多个输入进行函数处理后输出 有点像map 每个发射完才进行操作
combineLastest 操作最近的两个 与zip不同在于任何一个发射了数据都可以工作
and then when (rxjava-joins JoinObservable 类似zip)
switch 取消订阅之前的 订阅新的
startWith 和concat类似 只不过放在前边

5.调度observeOn subscribeOn doOnCOmpeleted doOnError doOnTerminate oOnSubscribe delay
.io() 读写类
.computation() 计算类
.immediate() 立即
.newThread() 新开线程
.trampoline() 入队 不立即执行

6.布尔 all sequenceEqual exits contains isEmpty amb...

7.转换 toList toSortedList(bean implements Comparable) toMap

8.错误重试 onErrorResumeNext OnExceptionResumeNext OnErrorReturn retry ...

note: onBackPressBuffer
我的练习例子:https://git.oschina.net/gryllus/Rx.git

4.什么原理
只有熟悉响应式编程的原理及思想,才能够讲其应用到我们的项目当中,成为我们手中的利器。

Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};
// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()
observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

因此 Action0 可以被当成一个包装对象,将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。这样其实也可以看做将 onCompleted() 方法作为参数传进了 subscribe(),相当于其他某些语言中的『闭包』。

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});

public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
可以看到,subscriber() 做了3件事:

1. 调用 Subscriber.onStart() 。这个方法在前面已经介绍过,是一个可选的准备方法。
2.调用 Observable 中的 OnSubscribe.call(Subscriber) 。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中, Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。
3.将传入的 Subscriber 作为 Subscription 返回。这是为了方便 unsubscribe().
  1. 变换的原理:lift()

// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
subscribe() 中这句话的 onSubscribe 指的是 Observable 中的 onSubscribe 对象,这个没有问题,但是 lift() 之后的情况就复杂了点。
当含有 lift() 时:
1.lift() 创建了一个 Observable 后,加上之前的原始 Observable,已经有两个 Observable 了;
2.而同样地,新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了两个 OnSubscribe;
3.当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是 lift() 所返回的新的 Observable ,于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那个 OnSubscribe;
4.而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在这个 call() 方法里,新 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber(Operator 就是在这里,通过自己的 call() 方法将新 Subscriber和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新 Subscriber 向原始 Observable 进行订阅。
这样就实现了 lift() 过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。
精简掉细节的话,也可以这么说:在 Observable 执行了 lift(Operator) 方法之后,会返回一个新的 Observable,这个新的 Observable 会像一个代理一样,负责接收原始的 Observable 发出的事件,并在处理后发送给 Subscriber。

note:这就形成了流式的调用流程

  1. 除了 lift() 之外, Observable 还有一个变换方法叫做 compose(Transformer)。它和 lift() 的区别在于, lift() 是针对事件项和事件序列的,而 compose() 是针对 Observable 自身进行变换。
  2. subscribeOn() 的线程切换发生在 OnSubscribe 中,即在它通知上一级 OnSubscribe 时,这时事件还没有开始发送,因此 subscribeOn() 的线程控制可以从事件发出的开端就造成影响;而 observeOn() 的线程切换则发生在它内建的 Subscriber 中,即发生在它即将给下一级 Subscriber 发送事件时,因此 observeOn() 控制的是它后面的线程。
    当使用了多个 subscribeOn() 的时候,只有第一个 subscribeOn() 起作用。
    extends可用于返回类型的限定,不能用于参数类型的限定
    super可用于参数类型的限定,不能用于返回类型的限定
    4.能不能多切换几次线程?
    通过 observeOn() 的多次调用,程序实现了线程的多次切换。
    不过,不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。
    5.Rxjava2 & Rxjava1
    RxJava2最大的改动就是对于backpressure的处理,为此将原来的Observable拆分成了新的Observable和Flowable,同时其他相关部分也同时进行了拆分。
    RxJava2 vs RxJava1

Refenece:

官网
分支
通俗解释什么是响应式编程
重新理解响应式编程
RxJava操作符大全
背压
RxJava中backpressure这个概念的理解
给 Android 开发者的 RxJava 详解
RxJava Essentials(英文版)讲得比较详细,适合RxJava入门学习。
RxJava Essentials(中文版)RxJava Essentials的中文翻译。
RxJava教程大集合
RxJava-Android-Samples
给初学者的RxJava2.0教程

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

推荐阅读更多精彩内容