• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

RxJava响应式编程学习笔记

武飞扬头像
kgduu
帮助1

1、概述

RxJava是一个著名的开源库,是ReactiveX(Reactive Extensions)的一种java实现。ReactiveX是一种响应式扩展框架,有很多实现,如RxAndroid,RxJS,RxSwift,RxRuby,RxCpp,RxGo等。RxJava有1.x和2.x两个主要的分支,分别代表着RxJava1和RxJava2。

RxJava可以看作由Observable,Subscriber和Scheduler组成,它们关系图为

学新通

Subscriber订阅到Observable,Observable会在默认或者指定的Scheduler上工作并产生数据流返回给Subscriber,Subscriber也会在默认或者在指定的Scheduler上接收Observable要送过来的数据流。Scheduler是对线程的抽象,不同的Scheduler代表了不同的线程

1.1  Observable和Subscriber

Observable提供了subscribe方法,当有Subscriber通过subscribe方法订阅到Observable时,Observable可以向Scheduler发送数据流。响应式编程中的事件分为三类:普通事件、错误事件和结束事件。在Subscriber中有三个方法与这三种事件一个一个地对应。Observable会通过调用Subscriber的这三个方法发送对应的事件。

  • onNext:当Observable要发送普通事件时,就会调用这个方法,可以被调用0-N次
  • onError:当在Observable内部有异常或者错误产生的时候,可以调用这个方法来向Subscriber发送错误事件,这个方法只能被调用1次。
  • onComplete:如果Observable已经发送完所有的数据,并且没有发生错误,这时需要 调用 这个方法来向Subscriber发送结束事件,这个方法也只能调用1次,而且和onError是互斥关系。

Subscriber提供了unsubscribe方法,当Subscriber订阅到Observable之后,可随时调用这个方法来终止对Observable的订阅。

除了通用的Observable之外,还有两种特殊的Observable,分别是Single和Completable,与之分别对应的Subscriber是SingleSubscriber和CompletableSubscriber。

2、操作符

2.1 创建操作符

range 创建的Observable会发送一个范围内的数据
defer 只有当Subscriber来订阅的时候才会创建一个新的Observable对象
just 接收某个对象作为输入 ,然后再创建一个发送该对象的Observable
from 接收一个对象作为参数来创建Observable,可以是Iterable,Callable,Future。just操作符创建的Observable会将整个参数对象一次性发送出去。而使用from创建的Observable会每次只发送一次。
interval 创建的Observable对象会从0或者初始延时时间开始,每隔固定的时间发送一个数字。这个对象是运行在Scheduler中。
repeat 让Observable对象发送的数据重复发送N次,可以指定其发送的次数
timer 创建的Observable会在指定时间后发送一个数字0,默认是运行在computation Scheduler上

 2.2 转换操作符

buffer 将数据按照规定的大小做一下缓存,当缓存的数据量达到设置的上限后就将缓存的数据作为一个集合发送出去。可以设置跳过的数目。不仅可以通过数量规则来缓存,也可以通过时间规则来缓存
flatMap 将Observable转化为多个以源Observable发送的数据作为源数据的Observable,然后将这多个Observable发送的数据整合并发送出来。还有一个扩展操作符flatMapIterable
groupBy   将源Observable发送的数据按照key来拆分成一些小的Observable,然后这些小的Observable分别发送其所包含的数据
map 将源Observable发送的每个数据都按照给定的函数进行转化,并将转化后的数据发送出来。
cast 将Observable发送的数据强制转化为另外一种类型。
scan 对一个序列的数据应用同一个函数进行计算,并将这个函数的结果发送出去,作为下一个数据应用这个函数时的第一个参数使用。

2.3 过滤操作符

debounce 用来做限流的

 throttleWithTimeout

通过时间来限流
distinct 用于去重
elementAt 只会过滤出源Observable发送出来的顺序为N的数据。
filter 根据一个函数来进行过滤操作。源Observable发送的数据作为参数传递到函数里,如果函数的返回值为true,则这个数据将继续被发送出去,否则数据将会被过滤掉。
first 只会返回第一条或者满足条件的第一条数据
last 只返回最后一条或者满足条件的最后一条数据
skip 将源Observable发送的数据过滤掉前n项。
take 只取前n项
skipLast 从后面操作过滤到n项
takeLast 从后面操作取n项
sample 指定一段时长,在每段时长结束的时候发送源Observable发送的最新数据,其他的都会被过滤掉。
throttleFirst 取的是在规定时间段内的第一个数据,其他的会被过滤掉

2.4 组合操作符

combineLatest 将2-9个Observable发送的数组组合起来,再发送出来。有两个前提:所有组合的Observable都发送过数据;任何一个Observable发送一个数据,combineLatest就将所有Observable最新发送的数据按照提供的函数组装起来发送出去。
join 根据时间窗口来组合两个Observable发送的数据
groupJoin 与join相似,只是发送出来的是一个个小的Observable,每个Observable里面包含了一轮组合数据。
merge 将多个Observable发送的数据整合起来发送。当某一个Observable发出onError时,merge的过程会被停止并将错误分发给Subscriber。
mergeDelayError 会在merge结束后再分发错误
zip 将多个Observable发送的数据按顺序组合起来。

 2.5 错误处理操作符

onErrorReturn 在发生错误时,让Observable发送一个预先定义好的数据并停止 继续发送数据,正常结束整个过程
onErrorResumeNext 在有错误事件的时候会创建另外一个Observable来代替当前的Observable并继续发送数据。
onExceptionResumeNext 与onErrorResumeNext类似,会对onError抛出的数据类型做判断,如果是Exception,就会使用另外一个Observable代替原Observable继续发送数据,否则会将错误分发给Subscriber
retry 在发生错误时会重新进行订阅,而且可以重复多次,所以发送的数据可能会产生重复,但是有可能每次retry都会发生错误,从而造成不断订阅不断retry的死循环,可以指定最大重复次数。

2.6 辅助操作符

delay 让发送数据的时机延后一段时间,所有数据都会依次延后一段时间再发送。
delaySubscription 延时注册Subscriber
do系列

给Observable的生命周期的各个阶段加上一系列的回调监听,当Observable执行到这个阶段的时候,这些回调就会被触发。

doOnEach:Observable每发送一个数据的时候就会触发这个回调,无论Observable调用 的是onNext,onError还是onCompleted

doOnNext:只有Observable调用onNext发送数据的时候才会被触发

doOnSubscribe和doOnUnsubscribe:会在Subscriber进行订阅和反订阅的时候触发回调。当一个Observable通过onError或者onCompleted结束的时候,会反订阅所有的Subscriber

doOnError:会在Observable通过OnError分发错误事件的时候触发回调,并将Throwable对象作为参数传进回调函数里。

doOnComplete:会在Observable通过OnCompleted发送结束事件的时候触发回调。

doOnTerminate:会在Observable结束前触发回调,无论是正常结束还是异常结束

finallyDo:会在Observable结束后触发回调,无论时正常结束还是异常结束。

materialize 将OnNext,OnError和OnComplete事件都转化为一个Notification对象并按照原来的顺序发送出来。
dematerialize 执行相反的过程,将这些Notification对象重新转化成对应的OnNext,OnError和OnComplete事件。
subscribeOn 指定Observable在哪个线程上运行
observeOn 指定观察者所运行的线程,也就是发送出的数据在哪个线程上使用。
timeInterval 拦截源Observable发送出来的数据,将其封装为一个TimeInterval对象
timeStamp 将每个数据项重新包装成一个TimeStamp对象。
timeout 给Observable加上超时时间,每发送一个数据后就重置计时器,当超过预定的时间还没有发送下一个数据时,就抛出一个超时的异常。
using 创建一个在Observable生命周期内存活的资源

2.7 条件操作

all 根据一个函数对源Observable发送的所有数据进行判断,最终返回的结果是这个判断结果。
amb 可以将至多9个Observable结合起来,哪个Observable首先发送了数据(包括onError和onComplete),就继续发送这个Observable数据,其他Observable所发送的数据都会被丢弃。
contains 判断源Observable所发送的所有数据是否包含某一个数据,如果包含返回true,如果源Observable已经结束了却还没有发送这个数据,返回false
isEmpty 判断源Observable是否发送数据,如果发送过就会返回false,如果源Observable已经结束了都还没有发送这个数据,返回true
defaultIfEmpty 判断源Observable是否发送了数据,如果源Observable发送了数据则正常发送这些数据,否则发送一个默认的数据。
sequenceEqual 判断两个 Observable发送的数据序列是否相同。
skipUntil 根据一个标志Observable来判断的,当这个标志Observable没有发送数据的时候,所有源Observable发送的数据都会被跳过。当标志Observable发送了一个数据后,则开始正常地发送数据
skipWhile 根据一个函数来判断是否跳过数据,如果函数返回值为true,则一直跳过源Observable发送的数据;如果函数返回false,则开始正常发送数据。
takeUntil 与skipUntil功能相反。
takeWhile 与skipWhile功能相反 

2.8 聚合操作符

concat 将多个Observable结合成一个Observable并发送数据,并且严格按照先后顺序发送数据。
count 用来统计源Observable发送了多少个数据,最后将数目发送出来。
reduce 应用一个函数接收Observable发送的数据和函数的计算结果,作为下次计算的参数,并输出最后的结果。
collect 与reduce类似,将源Observable发送的数据收集到一个数据结构里面,最后将这个数据结构整个发送出来。

2.9 与Connectable Observable相关操作符

publish 将普通的Observable转化为Connectable Observable
connect 用来触发Connectable Observable发送数据。应用connec操作符后会返回一个Subsciption对象,通过这个Subscription对象,可以调用其unsubscribe方法来中止数据的发送。
refCount 将一个Connectable Observable对象再重新转化为一个普通的Observable对象。
replay 返回一个Connectable Observable对象并且可以缓存其发送的数据

2.10 自定义操作符

需要遵守以下几条规则

  • 自定义操作符在发送任何数据之前都要使用 subscriber.isUnsubscribed()来检查Subscriber的状态,如果没有任何Subscriber订阅就没有必要去发送数据了。
  • 自定义操作要遵循Observable的核心原则
  1. 可以多次调用Subscriber的onNext方法,但是同一个数据只能调用一次。
  2. 可以调用Subscriber的onComplete或者onError方法,但这两个方法是互斥的。
  3. 如果无法保证遵守以上两条原则,可以对自定义操作符加上serialize操作符,这个操作符会强制发送正常的数据。
  • 自定义操作符内部不能阻塞住
  • 如果通过组合多个RxJava原生的操作符就能达到目的,就不要使用自定义操作符来实现。
lift 可以实现一个自定义的操作符。
compose 需要 创建一个实现了Transformer接口的对象。

3、Scheduler

3.1 类型

有computation, io,newThread等类型。

computation Scheduler:适用于和CPU相关的任务,不适合那些会阻塞的任务。

newThread Scheduler:每次都会新建一个线程,一般情况下不推荐使用这个,因为创建一个线程都会造成稍微的延迟。

io Scheduler:类似于newThread Scheduler,io Scheduler可以被回收利用。内部会维持一个线程池,当使用io Scheduler来处理任务的时候 ,会首先从线程池中查找空闲的线程,如果有空闲线程就会在这个空闲线程上执行任务,否则会创建一个新的线程来执行任务,并在任务执行完毕时将这个空闲的线程放入到线程池中。当然空闲的线程不会一直在那里等待,RxJava默认空闲线程的存活时间是60秒,空闲时间超过60秒的线程会被回收。适合那些使用很少CPU资源的I/O操作。

immediate Scheduler:会在当前的线程上立即开始执行任务,这会将当前线程正在进行的任务阻塞。

trampoline Scheduler:与immediate Scheduler相似,在当前线程上执行任务,不是立即开始执行任务的,而是等待当前线程上之前的任务都结束之后再开始执行。

3.2 类抽象

学新通

3.3  类层次图

学新通

4、RxJava实现原理

4.1 订阅

调用Observable的subscribe方法,会调用另一个静态subscribe方法将Observable自身作为一个参数传入。

  1.  
    static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
  2.  
    // validate and proceed
  3.  
    if (subscriber == null) {
  4.  
    throw new IllegalArgumentException("subscriber can not be null");
  5.  
    }
  6.  
    if (observable.onSubscribe == null) {
  7.  
    throw new IllegalStateException("onSubscribe function can not be null.");
  8.  
    /*
  9.  
    * the subscribe function can also be overridden but generally that's not the appropriate approach
  10.  
    * so I won't mention that in the exception
  11.  
    */
  12.  
    }
  13.  
     
  14.  
    // new Subscriber so onStart it
  15.  
    subscriber.onStart();
  16.  
     
  17.  
    /*
  18.  
    * See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
  19.  
    * to user code from within an Observer"
  20.  
    */
  21.  
    // if not already wrapped
  22.  
    if (!(subscriber instanceof SafeSubscriber)) {
  23.  
    // assign to `observer` so we return the protected version
  24.  
    subscriber = new SafeSubscriber<T>(subscriber);
  25.  
    }
  26.  
     
  27.  
    // The code below is exactly the same an unsafeSubscribe but not used because it would
  28.  
    // add a significant depth to already huge call stacks.
  29.  
    try {
  30.  
    // allow the hook to intercept and/or decorate
  31.  
    RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
  32.  
    return RxJavaHooks.onObservableReturn(subscriber);
  33.  
    } catch (Throwable e) {
  34.  
    // special handling for certain Throwable/Error/Exception types
  35.  
    Exceptions.throwIfFatal(e);
  36.  
    // in case the subscriber can't listen to exceptions anymore
  37.  
    if (subscriber.isUnsubscribed()) {
  38.  
    RxJavaHooks.onError(RxJavaHooks.onObservableError(e));
  39.  
    } else {
  40.  
    // if an unhandled error occurs executing the onSubscribe we will propagate it
  41.  
    try {
  42.  
    subscriber.onError(RxJavaHooks.onObservableError(e));
  43.  
    } catch (Throwable e2) {
  44.  
    Exceptions.throwIfFatal(e2);
  45.  
    // if this happens it means the onError itself failed (perhaps an invalid function implementation)
  46.  
    // so we are unable to propagate the error correctly and will just throw
  47.  
    RuntimeException r = new OnErrorFailedException("Error occurred attempting to subscribe [" e.getMessage() "] and then again while trying to pass to onError.", e2);
  48.  
    // TODO could the hook be the cause of the error in the on error handling.
  49.  
    RxJavaHooks.onObservableError(r);
  50.  
    // TODO why aren't we throwing the hook's return value.
  51.  
    throw r; // NOPMD
  52.  
    }
  53.  
    }
  54.  
    return Subscriptions.unsubscribed();
  55.  
    }
  56.  
    }
学新通

订阅时序图为

学新通

订阅的过程就是调用 Observable内部的成员变量onSubscribe的call方法,将Subscriber作为参数传入进去,然后由onSubscribe对象向Subscriber发送数据的过程。在不使用Scheduler时,Observable和Subscriber都会运行在订阅时的线程上。

学新通

4.2 操作符实现

4.2.1 lift工作原理

学新通 OnSubscribeLift类结构

学新通

 创建Observable时序

学新通

lift订阅时的时序

学新通

 创建一个liftObservable,liftObservable的onSubscribe成员变量是一个OnSubscribeLift对象,该对象持有一个Observable的onSubscribe成员变量的引用。当有Subscriber订阅的时候会调用这个OnSubscribeLift对象的call方法,调用Operator的call方法返回一个包装后的Subscriber对象,然后再调用源onSubscribe的call方法将liftSubscriber 传进去。源Observable在发送数据时,会先发送到liftSubscriber,由liftSubscriber对数据做一些自定义的操作,然后再发送给原始的Subscriber.

学新通

4.2.2 map工作原理 

学新通

类结构为:

学新通

依赖于OnSubscribeMap类,并且会将当前的Observable对象和Func1对象一起作为构造函数,然后创建并返回一个新的Observable,称之为MapObservable。

订阅时序图为

学新通

 订阅时调用call方法会做如下操作

  • 创建一个新的MapSubscriber:parent
  • 将parent通过add方法添加到源Subscriber中,这样在取消订阅时能够将所有Subscriber都取消
  • 将parent订阅到源Observable中。

学新通

4.2.3 flatMap工作原理 

首先判断一下当前的Observable是否是ScalarSynchronousObservable。普通的Observable是先map然后再merge。

学新通

学新通

通过map结合传入的Func1对象将源Observable发送的数据转化为一个个小的Observable,然后通过merge将所有小的Observable组合成一个Observable后返回 。

OperateMerge类结构 

学新通

OperatorMerge操作符作用时创建MergeSubscriber,包含了源Subscriber。

学新通

 当MergeSubscribe接收到数据时,创建InnerSubscriber,同时让接收到的数据Observable订阅InnserSubscriber。同时启动发送数据emit。将数据发送给源Subscriber

学新通

 InnserSubscriber接收到数据时,会调用MergeSubscriber的tryEmit将数据发送给源Subscriber

学新通

其处理图为

学新通

4.2.4 concat工作原理

其方法为

学新通

 学新通

 学新通

其类结构图为

学新通

订阅时序图为

学新通

 学新通

5、Subject

学新通

 PublishSubject:接收订阅之后的所有数据

ReplaySubject:接收订阅前后的所有数据

BehaviorSubject:接收订阅前的最近一个及订阅后的所有数据

AsyncSubject:只接收最后一条数据

6、BlockingObservable

学新通

 转换成Future通过使用BlockingOperatorToFuture操作符

  1.  
    public static <T> Future<T> toFuture(Observable<? extends T> that) {
  2.  
     
  3.  
    final CountDownLatch finished = new CountDownLatch(1);
  4.  
    final AtomicReference<T> value = new AtomicReference<T>();
  5.  
    final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
  6.  
     
  7.  
    @SuppressWarnings("unchecked")
  8.  
    final Subscription s = ((Observable<T>)that).single().subscribe(new Subscriber<T>() {
  9.  
     
  10.  
    @Override
  11.  
    public void onCompleted() {
  12.  
    finished.countDown();
  13.  
    }
  14.  
     
  15.  
    @Override
  16.  
    public void onError(Throwable e) {
  17.  
    error.compareAndSet(null, e);
  18.  
    finished.countDown();
  19.  
    }
  20.  
     
  21.  
    @Override
  22.  
    public void onNext(T v) {
  23.  
    // "single" guarantees there is only one "onNext"
  24.  
    value.set(v);
  25.  
    }
  26.  
    });
  27.  
     
  28.  
    return new Future<T>() {
  29.  
     
  30.  
    private volatile boolean cancelled;
  31.  
     
  32.  
    @Override
  33.  
    public boolean cancel(boolean mayInterruptIfRunning) {
  34.  
    if (finished.getCount() > 0) {
  35.  
    cancelled = true;
  36.  
    s.unsubscribe();
  37.  
    // release the latch (a race condition may have already released it by now)
  38.  
    finished.countDown();
  39.  
    return true;
  40.  
    } else {
  41.  
    // can't cancel
  42.  
    return false;
  43.  
    }
  44.  
    }
  45.  
     
  46.  
    @Override
  47.  
    public boolean isCancelled() {
  48.  
    return cancelled;
  49.  
    }
  50.  
     
  51.  
    @Override
  52.  
    public boolean isDone() {
  53.  
    return finished.getCount() == 0;
  54.  
    }
  55.  
     
  56.  
    @Override
  57.  
    public T get() throws InterruptedException, ExecutionException {
  58.  
    finished.await();
  59.  
    return getValue();
  60.  
    }
  61.  
     
  62.  
    @Override
  63.  
    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
  64.  
    if (finished.await(timeout, unit)) {
  65.  
    return getValue();
  66.  
    } else {
  67.  
    throw new TimeoutException("Timed out after " unit.toMillis(timeout) "ms waiting for underlying Observable.");
  68.  
    }
  69.  
    }
  70.  
     
  71.  
    private T getValue() throws ExecutionException {
  72.  
    final Throwable throwable = error.get();
  73.  
     
  74.  
    if (throwable != null) {
  75.  
    throw new ExecutionException("Observable onError", throwable);
  76.  
    } else if (cancelled) {
  77.  
    // Contract of Future.get() requires us to throw this:
  78.  
    throw new CancellationException("Subscription unsubscribed");
  79.  
    } else {
  80.  
    return value.get();
  81.  
    }
  82.  
    }
  83.  
     
  84.  
    };
  85.  
     
  86.  
    }
学新通

使用CountDownLatch来实现,源Observable订阅特定的Subscriber,在处理onNext时,设置返回结果,在处理onComplete时,countDownLatch减1,在处理onError时设置error值,同时countDownLatch减1结束。在future中获取值时,等待countDownLatch

参考资料:

https://github.com/ReactiveX/RxJava

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfkebg
系列文章
更多 icon
同类精品
更多 icon
继续加载