响应式编程-RxJava1.3.8
一、响应式编程
响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。Rx提供了一系列的操作符,你可以使用它们来过滤(filter)、选择(select)、变换(transform)、结合(combine)和组合(compose)多个Observable,这些操作符让执行和复合变得非常高效。
Rx的目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,响应式编程的解决方案、观察者设计模式、一个实现异步操作的库。RxJava是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。目前已经更新到了3.1.3版本,hystrix使用的还是1.3.8的版本,本文先从1.3.8版本开始介绍他的API,后续会持续更新其他的版本。
RxJava是通过扩展的观察者模式来实现的,所以你要先了解观察者模式,不懂得可以先看一下我之前写的设计模式。
二、基本原理
1、观察者
Observer
public interface Observer<T> { //完成事件 void onCompleted(); //出错事件 void onError(Throwable e); //普通事件 void onNext(T t); }
onNext():普通的事件,用于一般的事件发送。
onCompleted(): 完成事件,当不再有新的onNext()事件时调用onCompleted方法作为整个事件队列结束的标志,在一个事件队列当中可以有多个onCompleted方法,但是只能触发一次,一旦触发之后,后续的事件会继续发送,但是观察者将不会接受事件。
onError(): 事件队列异常。在事件处理过程中出现异常时,onError()会被触发,同事队列自动终止,与onCompleted()方法相同,onError事件也可以存在多个,但是只会触发一次。
需要注意的是onComplete
和onError
存在互斥的关系, 两个方法可以同时存在于事件队列当中,但是一旦触发其中一个方法之后,后续将不再接收事件。
Subscriber
public abstract class Subscriber<T> implements Observer<T>, Subscription { @Override public final void unsubscribe() { subscriptions.unsubscribe(); } // @Override public final boolean isUnsubscribed() { return subscriptions.isUnsubscribed(); } // public void onStart() { // do nothing by default } }
Subscriber是Observer的增强实现类,因此Observer经常被转成Subscriber使用,也多出了一些功能。
onStart():用于在 subscribe 刚开始,而事件还未发送之前被调用。可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法。
unsubscribe(): 用于取消订阅,在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
2、被观察者
Observable即被观察者,它决定什么时候触发事件以及触发怎样的事件。create()
方法是 RxJava 最基本的创造事件序列的方法。基于这个方法, RxJava 还提供了一些方法用来快捷创建事件队列。
Observable observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onNext("jack"); subscriber.onNext("how are you"); subscriber.onCompleted(); } }); //等同于上面的调用流程 Observable observable = Observable.just("Hello", "jack", "how are you"); //等同于上面的调用流程 String[] words = {"Hello", "jack", "how are you"}; Observable observable = Observable.from(words);
3、订阅
observable.subscribe(observer);
observable.subscribe(subscriber);
三、操作流程
被观察者(Observable)通过订阅(Subscribe)按顺序发送事件给观察者(Observer),观察者(Observer)按顺序接收事件&作出对应的响应动作。
1、create
private Subscriber getSubscriber(){ return new Subscriber<String>() { //新增onStart方法,用来做一些初始化操作 @Override public void onStart() { super.onStart(); System.out.println("on start"); } //被观察者调用onCompleted时触发 @Override public void onCompleted() { System.out.println("on complete"); } //被观察者调用onError时触发 @Override public void onError(Throwable e) { System.out.println("on error"); } //被观察者调用onNext时触发 @Override public void onNext(String s) { System.out.println("on next"); System.out.println(s); } }; }
@Test public void test1(){ Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { System.out.println("call"); //定义事件队列 subscriber.onNext("aaaa"); subscriber.onCompleted(); } }); Subscriber<String> subscriber = getSubscriber(); observable.subscribe(subscriber); }
on start
call
on next
aaaa
on complete
2、just
just()
,将为你创建一个Observable并自动为你调用onNext( )发射数据。通过just( )方式 直接触发onNext(),just中传递的参数将直接在Observer的onNext()方法中接收到。@Test public void test2(){ Subscriber<String> subscriber = getSubscriber(); Observable<String> observable = Observable.just("hello","jack"); observable.subscribe(subscriber); }
on start
on next
hello
on next
jack
on complete
3、from
from()
方法将传入的数组
或Iterable
拆分成具体对象后,自动调用onNext
方法依次发送。@Test public void test3() { //定义要发送的事件集合 List<String> mList = new ArrayList<>(); mList.add("hello"); mList.add("jack"); //定义Observable Observable<String> observable = Observable.from(mList); //进行订阅,开始发送事件 Subscriber<String> subscriber = getSubscriber(); observable.subscribe(subscriber); }
4、defer
通过defer()方法创建Observable,当观察者订阅时,才创建Observable,并且针对每个观察者创建都是一个新的Observable。以何种方式创建这个Observable对象,当满足回调条件后,就会进行相应的回调。
@Test public void test4() { //定义一个被观察者 Observable<String> observable = Observable.defer(new Func0<Observable<String>>() { @Override public Observable<String> call() { Observable<String> mObservable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("事件订阅开始"); } }); System.out.println("被观察者创建:" + mObservable); return mObservable; } }); //订阅事件1,每产生一个订阅就会生成一个新的observable对象 observable.subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println("观察者2订阅事件 " + s); } }); //订阅事件2,每产生一个订阅就会生成一个新的observable对象 observable.subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println("观察者1订阅事件 " + s); } }); }
被观察者创建:rx.Observable@2eda0940
观察者2订阅事件 事件订阅开始
被观察者创建:rx.Observable@545997b1
观察者1订阅事件 事件订阅开始
这里用到了不完整定义的回调Action
,它就相当于我们之前定义的subscriber,但是其只针对onNext
事件做处理。
5、interval
创建一个按固定时间间隔发射整数序列的Observable,可用作定时器。即按照固定时长调用onNext()方法。@Test public void test5() throws InterruptedException { Observable<Long> observable = Observable.interval(1, TimeUnit.SECONDS); observable.subscribe(new Action1<Long>() { @Override public void call(Long aLong) { System.out.println("订阅时长为:"+aLong); } }); TimeUnit.SECONDS.sleep(3); }
6、timer
该方法可以在一定延迟之后发送特定事件。
@Test public void test6() throws InterruptedException { //定义被观察者,在2000毫秒后开始发送事件 Observable<Long> observable = Observable.timer(2000,TimeUnit.MILLISECONDS); System.out.println("发送事件开始:"+System.currentTimeMillis()); observable.subscribe(new Action1<Long>() { @Override public void call(Long aLong) { System.out.println("收到订阅结束:"+System.currentTimeMillis()); } }); TimeUnit.SECONDS.sleep(3); }
四、不完全定义回调
先来简单看一下subscribe()
方法的源码
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) { subscriber.onStart(); observable.onSubscribe.call(subscriber); return Subscription; }
1、首先是传进来的两个参数Subscriber和Observable分别对应我们调用时的subscriber和observable。
2、订阅开始后,首先执行的是subscriber.onStart()方法,也就是我们观察者的onStart方法,这也就解释了为什么onStart方法只可以在默认线程当中执行,因为我们指定线程只可以指定observable所对应线程以及observable对应直属下级Subscriber所在线程。
3、接下来调用observable当中的onSubscribe.call方法,我们的整个事件序列就定义在这里,调用call方法开始发送事件。
4、返回值Subscription,之前在介绍观察者Subscriber时我们可以看到,Subscriber实现了这个接口,用于提供解除订阅以及判断订阅是否连接的方法,在订阅完成之后返回Subscription供外部调用。
subscribe方法的参数除了Subscriber
和Observer
之外,还有Action类,这就是将要介绍的不完整定义回调
。
@Test public void test7(){ Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("aaaaa"); // subscriber.onError(new NullPointerException()); subscriber.onCompleted(); } }); //只对事件序列中的onNext做出响应 Action1<String> action1 = new Action1<String>() { @Override public void call(String s) { System.out.println("no next"); } }; //只对事件序列中的onError做出响应 Action1<Throwable> action2 = new Action1<Throwable>() { @Override public void call(Throwable throwable) { System.out.println("on error"+throwable.getMessage()); } }; //只对事件序列中的onCompleted做出响应 Action0 action0 = new Action0() { @Override public void call() { System.out.println("on complete"); } }; observable.subscribe(action1,action2,action0); }
//订阅事件,只处理onNext事件 observable.subscribe(action1); //订阅事件,只处理onNext和onError事件 observable.subscribe(action1,action2); //订阅事件,处理onNext、onError和onCompleted事件 observable.subscribe(action1,action2,action0);
这里的onError和onCompleted也只会执行其中的一个。
五、链式调用
@Test public void test8() { //定义将要发射的数组 String[] strs = {"1", "2", "3"}; //from操作符可以把数组当中的数据逐条发送出去 Observable.from(strs) //调用flatMap操作符把String类型转换为新的Observable<String>并开始发送事件。 .flatMap(new Func1<String, Observable<String>>() { @Override public Observable<String> call(String s) { System.out.println("testRX---map:" + s); //需要把String类型转换成的Observable对象 return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("test"); } }); } }).subscribe(new Subscriber<String>() { @Override public void onCompleted() { //处理完成事件 System.out.println("on complete"); } @Override public void onError(Throwable e) { //处理error事件 System.out.println("on error"); } @Override public void onNext(String s) { //处理普通的onNext事件 System.out.println("on next"); System.out.println(s); } }); }
testRX---map:1 on next test testRX---map:2 on next test testRX---map:3 on next test
六、变换操作符
变换操作符的作用是对Observable发射的数据按照一定规则做一些变换操作,然后将变换后的数据发射出去。变换操作符有map,flatMap,switchMap,filter,buffer,groupBy等。
1、map
map操作符就是通过制定一个Func1
对象,将原Observable
对象转换为另一个Observable对象并发射。
@Test public void test1() { //定义初始事件序列数组 Integer[] ints = {1, 2, 3}; //调用from逐个发射数据 //map方法把Intger类型转换为String类型 Observable.from(ints).map(new Func1<Integer, String>() { @Override public String call(Integer i) { //对Integer数据进行处理,转换成String类型返回 return i + "号玩家"; } }).subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println(s + "加入游戏"); } }); }
map方法怎么就把一种数据类型转换成了另一种数据类型呢,我们看一下map的源码
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) { return lift(new OperatorMap<T, R>(func)); } //这里新建了一个Operator对象,核心功能代码如下 public final class OperatorMap<T, R> implements Operator<R, T> { final Func1<? super T, ? extends R> transformer; public OperatorMap(Func1<? super T, ? extends R> transformer) { this.transformer = transformer; } @Override public Subscriber<? super T> call(final Subscriber<? super R> o) { MapSubscriber<T, R> parent = new MapSubscriber<T, R>(o, transformer); o.add(parent); return parent; } } public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) { return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator)); }
newSubscriber
并与原observable
订阅的Subscriber
关联起来,left方法本身也返回一个新建的被观察者newObservable
。由此变为,当产生事件订阅时,实际上是newObservable
订阅了事件,之后而通知原observable
开始发送事件,原observable
发送的事件发送向newSubscriber
,再发送给Subscriber
。 flatMap
也是用来做类型转换,不同于map
的是,flatMap
转换后得到的是一个Observable对象。@Test public void test2() throws InterruptedException { //interval方法创建Observable对象,每隔1秒发送一个事件 //经过flatMap方法变化,将long类型的事件变换为一个新的Observable对象发射出去 Subscription subscription = Observable.interval(1, TimeUnit.SECONDS).flatMap(new Func1<Long, Observable<String>>() { @Override public Observable<String> call(final Long aLong) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { System.out.println("testRX---next:" + aLong); subscriber.onNext(aLong + "_s"); } }); } //定义Subscriber对变换后的事件进行接收 }).subscribe(new Subscriber<String>() { @Override public void onCompleted() { System.out.println("on complete"); } @Override public void onError(Throwable e) { System.out.println("on error"); } @Override public void onNext(String s) { System.out.println("on next"); } }); TimeUnit.SECONDS.sleep(3); }
看一下源码
public final <R> Observable<R> flatMap(Func1<? super T, ? extends Observable<? extends R>> func) { if (getClass() == ScalarSynchronousObservable.class) { return ((ScalarSynchronousObservable<T>)this).scalarFlatMap(func); } return merge(map(func)); }
首先在这里它调用了map
方法,在前面我们分析过,map
方法会生成一个新的Observable对象,并改变事件的订阅顺序,接下来执行到merge方法,merge方法做了什么呢?
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) { return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator)); } public final class OnSubscribeLift<T, R> implements OnSubscribe<R> { public OnSubscribeLift(OnSubscribe<T> parent, Operator<? extends R, ? super T> operator) { this.parent = parent; this.operator = operator; } @Override public void call(Subscriber<? super R> o) { Subscriber<? super T> st = hook.onLift(operator).call(o); // new Subscriber created and being subscribed with so 'onStart' it st.onStart(); parent.call(st); } }
这里会把每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。
@Test public void test3() { Observable.just(1, 2, 3, 4, 5, 6).buffer(3).subscribe(new Action1<List<Integer>>() { @Override public void call(List<Integer> integers) { for (Integer integer : integers) { System.out.println("buffer" + integer); } System.out.println("---------"); } }); }
buffer1 buffer2 buffer3 --------- buffer4 buffer5 buffer6 ---------
4、fliter
@Test public void test4(){ Observable.just(1,2,3,4,5,6).filter(new Func1<Integer, Boolean>() { @Override public Boolean call(@NonNull Integer integer){ if(integer > 3){ return true; } return false; } }).subscribe(new Action1<Integer>() { @Override public void call(Integer integer){ System.out.println(integer); } }); }
5、lift
lift()方法可以变换原Observable生成新的Observable
@Test public void testLift() { Observable.from(new Integer[]{1, 2, 3}) .lift(new Observable.Operator<String, Integer>() { @Override public Subscriber<? super Integer> call(final Subscriber<? super String> child) { return new Subscriber<Integer>() { @Override public void onCompleted() { child.onCompleted(); } @Override public void onError(Throwable e) { child.onError(e); } @Override public void onNext(Integer integer) { String s = "tom" + integer; child.onNext(s); } }; } }) .subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println("hi "+s); } }); }
七、线程调度
默认情况下,在哪个线程调subscribe()
,就会在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,则需要 Scheduler(调度器)
。在RxJava 中,Scheduler,相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景。
Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
AndroidSchedulers.mainThread():Android 开发专用的 ,它指定的操作将在 Android 主线程运行。
有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。
subscribeOn(): 指定Observable(被观察者)所在的线程,或者叫做事件产生的线程。
observeOn(): 指定 Observer(观察者)所运行在的线程,或者叫做事件消费的线程。
@Test public void test1() { Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { System.out.println(Thread.currentThread().getName()); subscriber.onNext("aaaa"); subscriber.onCompleted(); } }).subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .subscribe(new Subscriber<String>() { @Override public void onCompleted() { System.out.println("on complete"); System.out.println(Thread.currentThread().getName()); } @Override public void onError(Throwable e) { } @Override public void onNext(String s) { System.out.println("on next " + s); } }); }
RxIoScheduler-2
on next aaaa
on complete
RxNewThreadScheduler-1
参考文章:https://www.jianshu.com/p/e5d1380c8343
参考文章:https://blog.csdn.net/alex_xfboy/article/details/89576152
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 易语言 —— 开山篇
· Trae初体验