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应运而生。
首先要熟悉三个概念:
- 事件
- 异步
- 数据流
何为事件?代码的角度来讲就是一段业务逻辑。通俗的讲,例如,每次顶一个外卖都是一个“事件”。如果你看看订单列表,你会发现其实是一个随着时间的推移(一系列的事件)发生的一系列的“事件”。
异步编程,我们可能只能在一个线程中顺序调用这三个相对耗时较多的业务,如图,然后再去做页面跳转,如果顺序执行不仅没有忠实反映业务本来的关系,而且会让你的程序“反应”更慢。区分出无关。
数据流只是事物之间沟通的桥梁。每一个业务完成后,都会有一条数据(一个事件)流向下游,下游的业务收到这条数据(这个事件),才会开始自己的工作。联系起有关
异步和数据流都是为了正确的构建事物的关系而存在的。通过 异步 和 数据流 来构建事物关系的编程模型。只不过,异步是为了区分出无关的事物,而数据流(事件流)是为了联系起有关的事物。
2.观察者模式(触发联动)银行卡
即当一个对象发生变化时,依赖它的所有对象都会被通知并且会自动更新。
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.应用在哪
- 在后端系统中给你一种新的学习扩展和并发的方式,而这不需要更换开发语言;
- 你克服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().
- 变换的原理: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:这就形成了流式的调用流程
- 除了 lift() 之外, Observable 还有一个变换方法叫做 compose(Transformer)。它和 lift() 的区别在于, lift() 是针对事件项和事件序列的,而 compose() 是针对 Observable 自身进行变换。
- 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教程