RxJava初探

Rx

rx是响应式编程的意思,本质是观察者模式,是以观察者和订阅者为基础的异步响应方式。包含以下几个部分:

       创建:RX可以方便的创建事件流和数据流

       组合:Rx使用查询式的操作符组合和变换数据流

       监听:Rx可以订阅任何可观察的数据流并没执行操作

       RxJava最核心的两个东西就是Observables(被观察者,也就是事件源)和Subscribers(观察者),由Observables发出一系列的事件,Subscribers进行订阅接收并进行处理,看起来就好像是设计模式中的观察者模式,但是跟观察者模式不同的地方就在于,如果没有观察者(即Subscribers),Observables是不会发出任何事件的。

       由于Observables发出的事件并不仅限于一个,有可能是多个的,如何确保每一个事件都能发送到Subscribers上进行处理呢?这里就借鉴了设计模式的迭代器模式,对事件进行迭代轮询(next()、hasNext()),在迭代过程中如果出现异常则直接抛出(throws Exceptions),下表是Observable和迭代器(Iterable)的对比:

与迭代器模式不同的地方在于,迭代器模式在事件处理上采用的是“同步/拉式”的方式,而Observable采用的是“异步/推式”的方式,对于Subscriber(观察者)而言,这种方式会更加灵活。

       Rxjava的看起来很像设计模式中的观察者模式,但是有一点明显不同,那就是如果一个Observerble没有任何的的Subscriber,那么这个Observable是不会发出任何事件的。

核心对象

Observable

       代表一连串流动的数据(数据、事件或者对象)或者看成数据源的生产者/事件的被观察者。本身具有推送的特性。

       Reactive中的Observable是非背压的。Flowable是具备背压的。

Observer

       接收源,英文释义“观察者”,没错!就是观察者模式中的“观察者”,可接收Observable、Subject发射的数据;

Subscriber

       Subscriber是订阅者需要实现的接口(观察者)。它跟Observer有什么区别是:Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅,当你不再想接收数据了,可以调用unsubscribe( )方法停止接收,Observer 在 subscribe() 过程中,最终也会被转换成 Subscriber 对象,一般情况下,建议使用Subscriber作为接收源;Subscriber要与Flowable(也是一种被观察者)联合使用,该部分内容是2.0新增的,后续文章再介绍。Obsesrver用于订阅Observable,而Subscriber用于订阅Flowable

Subscription

Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件;

实例代码

创建被观察者(数据流生产者):

创建观察者:

建立订阅关系:

        Observer<String> observer = createObserver();

        stringObservable.subscribe(observer);

说明:

  1. 当有观察者去订阅被观察者时,subscribe方法里面的计算逻辑会被执行。
  2. 在被观察者subscribe方法被执行的同时,被观察者会回调观察者的onSubscribe方法。
  3. 在onSubscribe方法中参数Disposable用来标识这个被观察者与观察者的订阅关系是否已经取消:

       d.isDisposed()==》false表示未取消

      d.isDisposed()==》true表示已经取消

     d.dispose();该观察者取消去观察者的订阅

 4、被观察者在subscribe方法中通过onNext产生数据,标识数据已经发生变化。此时会回调管观察者的onNext方法来接收变化的数据。

 5、当被观察者调者emitter.onComplete();时表示数据发送完毕,此时被观察者的onComplete得到调用。同时内部会执行d.dispose();取消订阅所以如下观察者只会执行一次:

其他操作

被观察者的创建方式

just()方式

 Observable<String> observable = Observable.just("Hello");使用just( ),将为你创建一个Observable并自动为你调用onNext( )发射数据。通过just( )方式 直接触发onNext(),just中传递的参数将直接在Observer的onNext()方法中接收到。

fromIterable()方式

使用fromIterable(),遍历集合,发送每个item。相当于多次回调onNext()方法,每次传入一个item。注意:Collection接口是Iterable接口的子接口,所以所有Collection接口的实现类都可以作为Iterable对象直接传入fromIterable()方法。

List<String> list = new ArrayList<String>();

        for(int i =0;i<10;i++){

            list.add("Hello"+i);

        }

 Observable<String> observable = Observable.fromIterable((Iterable<String>) list);

defer()方式

当观察者订阅时,才创建Observable,并且针对每个观察者创建都是一个新的Observable。以何种方式创建这个Observable对象,当满足回调条件后,就会进行相应的回调。

Observable<String> observable = Observable.defer(
    new Callable<ObservableSource <?extends String>>() {
     @Override
     public ObservableSource <?extends String> call() throws Exception
         {
                retur Observable.just("hello");
         }
    }
);    

interval( )方式

创建一个按固定时间间隔发射整数序列的Observable,可用作定时器。即按照固定2秒一次调用onNext()方法。

Observable<String> observable = Observable.interval(2, TimeUnit.SECONDS);

range( )方式

Observable<Integer> observable = Observable.range(1,20);

创建一个发射特定整数序列的Observable,第一个参数为起始值,第二个为发送的个数,如果为0则不发送,负数则抛异常。上述表示发射1到20的数。即调用20次nNext()方法,依次传入1-20数字。

timer( )方式

创建一个Observable,它在一个给定的延迟后发射一个特殊的值,即表示延迟2秒后,调用onNext()方法。

Observable<Integer> observable = Observable.timer(2, TimeUnit.SECONDS);

repeat( )方式

创建一个Observable,该Observable的事件可以重复调用。

Observable<Integer> observable = Observable.just(123).repeat();

操作符

操作符就是用于在Observable和最终的Observer之间,通过转换Observable为其他观察者对象的过程,修改发出的事件,最终将最简洁的数据传递给Observer对象。我们每次调用一次操作符,就进行一次观察者对象的改变,同时将需要传递的数据进行转变,最终Observer对象获得想要的数据。

map()操作符

map()操作符,就是把原来的Observable对象转换成另一个Observable对象,同时将传输的数据进行一些灵活的操作,方便Observer获得想要的数据形式。

flatMap()操作符

flatMap()对于数据的转换比map()更加彻底,如果发送的数据是集合,flatmap()重新生成一个Observable对象,并把数据转换成Observer想要的数据形式。它可以返回任何它想返回的Observable对象。

filter()操作符

filter()操作符根据test()方法中,根据自己想过滤的数据加入相应的逻辑判断,返回true则表示数据满足条件,返回false则表示数据需要被过滤。最后过滤出的数据将加入到新的Observable对象中,方便传递给Observer想要的数据形式

take()操作符

take()操作符:输出最多指定数量的结果。

doOnNext()

doOnNext()允许我们在每次输出一个元素之前做一些额外的事情。

线程调度Scheduler

Scheduler类型

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。

在RxJava 中,Scheduler,相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景。

1、Schedulers.immediate()

       直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。

2、Schedulers.newThread()

       总是启用新线程,并在新线程执行操作。

3Schedulers.io()

     I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。

4Schedulers.computation()

     计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
5、AndroidSchedulers.mainThread()

它指定的操作将在 Android 主线程运行。Android 还有专用的

线程控制方式

有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。

subscribeOn()

       指定Observable(被观察者)所在的线程,或者叫做事件产生的线程。

observeOn()

       指定 Observer(观察者)所运行在的线程,或者叫做事件消费的线程。

Disposable

在RxJava中,用它来切断Observer(观察者)与Observable(被观察者)之间的连接,当调用它的dispose()方法时, 它就会将Observer(观察者)与Observable(被观察者)之间的连接切断, 从而导致Observer(观察者)收不到事件。

Disposable的作用是切断连接,确切地讲是将Observer(观察者)切断,不再接收来自被观察者的事件,而被观察者的事件却仍在继续执行。

Disposable对象的获得

1.Observer接口

通过创建Observer接口,当订阅后,建立与Observable的联系,onSubscribe(Disposable d)中便可以获得Disposable对象。

2.Consumer等其他函数式接口

当subscribe()后直接返回一个Disposable 对象获得了Disposable对象后,我们便可以调用dispose()方法,在恰当的时机,断开连接,停止接收Observable(被观察者)发送的事件。

  1. 当切断被观察者与观察者之间的联系,Observable(被观察者)的事件却仍在继续执行。
  2. Observable(被观察者)可以发送无限个onNext, Observer(观察者)也可以接收无限个onNext.
  3. 当Observable(被观察者)发送了一个onComplete后, Observable(被观察者)中onComplete之后的事件将会继续发送, 而Observer(观察者)收到onComplete事件之后将不再继续接收事件.
  4. 当Observable(被观察者)发送了一个onError后, Observable(被观察者)中onError之后的事件将继续发送, 而Observer(观察者)收到onError事件之后将不再继续接收事件.
  5. Observable(被观察者)可以不发送onComplete或onError.
  6. 为关键的是onComplete和onError必须唯一并且互斥, 即不能发多个onComplete, 也不能发多个onError, 也不能先发一个onComplete, 然后再发一个onError, 反之亦然

关于onComplete和onError唯一并且互斥这一点, 是需要自行在代码中进行控制, 如果你的代码逻辑中违背了这个规则, 并不一定会导致程序崩溃. 比如发送多个onComplete是可以正常运行的, 依然是收到第一个onComplete就不再接收了, 但若是发送多个onError, 则收到第二个onError事件会导致程序会崩溃。

背压及Flowable

被观察者是事件的生产者,观察者是事件的消费者。假如出生产者无限生成事件,而消费者每2秒才能消费一个事件,这会造成事件无限堆积,最后造成OOM。Flowable就是解决处理这些慢慢堆积起来的消息。所谓背压,即生产者的速度大于消费者的速度带来的问题。

       在原来的RxJava 1.x版本中并没有Flowable的存在,Backpressure问题是由Observable来处理的。在RxJava 2.x中对于backpressure的处理进行了改动,为此将原来的Observable拆分成了新的Observable和Flowable,同时其他相关部分也同时进行了拆分。原先的Observable已经不具备背压处理能力。

       我们便知道了Flowable是为了应对Backpressure而产生的。Flowable是一个被观察者,与Subscriber(观察者)配合使用,解决Backpressure问题。

       处理Backpressure的策略仅仅是处理Subscriber接收事件的方式,并不影响Flowable发送事件的方法。即使采用了处理Backpressure的策略,Flowable原来以什么样的速度产生事件,现在还是什么样的速度不会变化,主要处理的是Subscriber接收事件的方式。

产生背压问题的情况

       1.如果生产者和消费者在一个线程的情况下,无论生产者的生产速度有多快,每生产一个事件都会通知消费者,等待消费者消费完毕,再生产下一个事件。所以在这种情况下,根本不存在Backpressure问题。即同步情况下,Backpressure问题不存在。
       2.如果生产者和消费者不在同一线程的情况下,如果生产者的速度大于消费者的速度,就会产生Backpressure问题。即异步情况下,Backpressure问题才会存在。

Subscriber

       与Observer不同的是 onSubscribe(Subscription s)中传给我们的不再是Disposable了, 而是Subscription。然而Subscription也可以用于切断观察者与被观察者之间的联系,调用Subscription.cancel()方法便可。

   另外Subscription增加了一个void request(long n)方法。这个方法就是用来向生产者申请可以消费的事件数量。当调用了request()方法后,生产者便发送对应数量的事件供消费者消费。这是因为Flowable在设计的时候采用了一种新的思路也就是响应式拉取的方式,你要求多少,我便传给你多少。

       如果不显示调用request就表示消费能力为0。

       虽然并不限制向request()方法中传入任意数字,但是如果消费者并没有这么多的消费能力,依旧会造成资源浪费,最后产生OOM。

       在异步调用时,RxJava中有个缓存池,用来缓存消费者处理不了暂时缓存下来的数据,缓存池的默认大小为128,即只能缓存128个事件。无论request()中传入的数字比128大或小,缓存池中在刚开始都会存入128个事件。当然如果本身并没有这么多事件需要发送,则不会存128个事件。

处理被压的策略

ERROR

这种方式会在产生Backpressure问题的时候直接抛出一个异常,这个异常就是著名的MissingBackpressureException。

BUFFER

       所谓BUFFER就是把RxJava中默认的只能存128个事件的缓存池换成一个大的缓存池,支持存很多很多的数据。这样,消费者通过request()即使传入一个很大的数字,生产者也会生产事件,并将处理不了的事件缓存。但是这种方式任然比较消耗内存,除非是我们比较了解消费者的消费能力,能够把握具体情况,不会产生OOM。总之BUFFER要慎用。

DROP

当消费者处理不了事件,就丢弃。消费者通过request()传入其需求n,然后生产者把n个事件传递给消费者供其消费。其他消费不掉的事件就丢掉。

LATEST

LATEST与DROP功能基本一致。消费者通过request()传入其需求n,然后生产者把n个事件传递给消费者供其消费。其他消费不掉的事件就丢掉。唯一的区别就是LATEST总能使消费者能够接收到生产者产生的最后一个事件。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值