RxJava基础六-辅助操作符

此篇内容均是来自书籍《RxJava响应式编程》李衍顺 著

3.6 辅助操作符

3.6.1 delay

delay操作符就是让发送数据的时机延后一段时间,这样所有的数据都会一次延后一段时间发送。在RxJava中将其实现为delay和delaySubscription,二者的不同之处在于delay四延时数据发送, 而delaySubscription是延时注册Subscriber。

/**
     * delay 
     */
    private Observable createObserver(final int index){
        return Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber subscriber) {
                log("subscribe:" + getCurrentTime());
                for(int i=1; i<=index; i++){
                    subscriber.onNext(getCurrentTime());
                }
            }
        }).subscribeOn(Schedulers.newThread());
    }
    private Observable delayObserver() {
        return createObserver(2).delay(2000, TimeUnit.MILLISECONDS, Schedulers.trampoline());
    }
    private Observable delaySubscriptionObserver() {
        return createObserver(2).delaySubscription(2000, TimeUnit.MILLISECONDS, Schedulers.trampoline());
    }
    private void delayTest(){
        log("start subscribe: "+ getCurrentTime());
        delayObserver().subscribe(new Action1() {
            @Override
            public void call(Long aLong) {
                log("delay:" + (getCurrentTime()-aLong));
            }
        });
        log("start subscribe: "+ getCurrentTime());
        delaySubscriptionObserver().subscribe(new Action1() {
            @Override
            public void call(Long aLong) {
                log("delaySubscription:" + (getCurrentTime()+aLong));
            }
        });
    }
订阅后的输出结果,使用delay操作符后 源Observable收到订阅请求后立刻将数据发送了出来,但是delay操作符会将数据截流下来,在2秒后才再发送出去;而delaySubscription会将订阅请求截留下来,在两秒后才订阅到源Observable上,然后源Observable立刻将数据发送了出去。
结果如下
start subscribe: 1556695248
subscribe:1556695248
start subscribe: 1556695248
delay:2
subscribe:1556695250
delaySubscription:3113390500
delaySubscription:3113390500

3.6.2 do

do操作符就是给Observable的生命周期的各个阶段加上一系列的回调监听,当Observable执行到这个阶段的时候,这些回调就会被触发。do操作符在RxJava中有一下多个实现:
-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结束后触发回调,无论是正常结束还是异常结束。

/**
     * do操作符
     */
    private Observable createObserver(){
        return Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber subscriber) {
                for(int i=1;i<=5;i++){
                    if(i<=3){
                        subscriber.onNext(i);
                    } else {
                        subscriber.onError(new Throwable("num > 3"));
                    }
                }
            }
        });
    }
    private Observable doOnEachObserver(){
        return Observable.just(1,2,3)
                .doOnEach(new Action1>() {
                    @Override
                    public void call(Notification notification) {
                        log("doOnEach send " + notification.getValue() + " type:" + notification.getKind());
                    }
                }).doOnNext(new Action1() {
                    @Override
                    public void call(Integer integer) {
                        log("doOnNext send " + integer);
                    }
                }).doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        log("on Subscribe");
                    }
                }).doOnUnsubscribe(new Action0() {
                    @Override
                    public void call() {
                        log("on unSubscribe");
                    }
                }).doOnCompleted(new Action0() {
                    @Override
                    public void call() {
                        log("onCompleted");
                    }
                });

    }
    private Observable doOnErrorObserver(){
        return createObserver()
                .doOnEach(new Action1>() {
                    @Override
                    public void call(Notification notification) {
                        log("doOnErrorEach send " + notification.getValue() + " type:" + notification.getKind());
                    }
                }).doOnError(new Action1() {
                    @Override
                    public void call(Throwable throwable) {
                        log("onError: " + throwable.getMessage());
                    }
                }).doOnTerminate(new Action0() {
                    @Override
                    public void call() {
                        log("OnTerminate");
                    }
                }).doAfterTerminate(new Action0() {
                    @Override
                    public void call() {
                        log("doAfterTerminate");
                    }
                });
    }
    private void doTest(){
        doOnEachObserver().subscribe(new Action1() {
            @Override
            public void call(Integer integer) {
                log("do: " + integer);
            }
        });
        doOnErrorObserver().subscribe(new Subscriber() {
            @Override
            public void onCompleted() {
                log("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                log("subscriber onError: " + e.getMessage());
            }

            @Override
            public void onNext(Integer integer) {
                log("subscriber onNext: " + integer);
            }
        });
    }
结果
on Subscribe
doOnEach send 1 type:OnNext
doOnNext send 1
do: 1
doOnEach send 2 type:OnNext
doOnNext send 2
do: 2
doOnEach send 3 type:OnNext
doOnNext send 3
do: 3
doOnEach send null type:OnCompleted
onCompleted
on unSubscribe
doOnErrorEach send 1 type:OnNext
subscriber onNext: 1
doOnErrorEach send 2 type:OnNext
subscriber onNext: 2
doOnErrorEach send 3 type:OnNext
subscriber onNext: 3
doOnErrorEach send null type:OnError
onError: num > 3
OnTerminate
subscriber onError: num > 3
doAfterTerminate

3.6.3 materialize 和dematerialize

materialize操作符将OnNext,OnError和OnComplete事件都转化为一个Notification对象并按照原来的顺序发送出来。此外还有dematerialize操作符,它会执行相反的过程,即将这些Notification对象重新转化为对应的OnNext,OnError和OnComplete事件。

 /**
     * materizlize && dematerialize
     */
    private Observable> materizlizeObserver(){
        return Observable.just(1,2,3).materialize();
    }
    private Observable deMaterializeObserver(){
        return materizlizeObserver().dematerialize();
    }
    private void materizlize_dematerialize(){
        materizlizeObserver().subscribe(new Action1>() {
            @Override
            public void call(Notification integerNotification) {
                log("materizlize: "+ integerNotification.getValue() + " type" + integerNotification.getKind());
            }
        });
        deMaterializeObserver().subscribe(new Action1() {
            @Override
            public void call(Integer integer) {
                log("deMeterizlize: "+ integer);
            }
        });
    }
输出结果如下。可看到materialize将所有的数据和事件都封装成了Notification对象,我们可以通过getValue和getKind方法分别将封装的值和当前的类型取出来,而dematerialize操作符将封装的数据又还原成了原来的数据,就如同一个普通的Observable一样
materizlize: 1 typeOnNext
materizlize: 2 typeOnNext
materizlize: 3 typeOnNext
materizlize: null typeOnCompleted
deMeterizlize: 1
deMeterizlize: 2
deMeterizlize: 3

3.6.4 subscribeOn 和 observeOn

subscribeOn用来指定Observable在哪个线程上运行, 我们可以指定它在IO线程上运行,也可以让其新开一个线程运行,当然也可以在当前线程上运行。一般会指定其在各种后台线程而不是主线程上运行,就如同AsyncTask的DoInBackground一样。

observeOn用来指定观察者所运行的线程,也就是发送出数据在哪个线程上使用。

subscribeOn就是在哪个线程上订阅, 订阅了Observable就开始干活了,所以subscribeOn指定的就是干活的线程;然后observeOn就是在哪个线程上观察,观察就看结果(数据,错误和结束事件等), 所以指定的就是结果被使用的线程。

/**
     * subscribeOn && observeOn
     */
    private Observable createObserver1(){
        return Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber subscriber) {
                log("on subscribe: " + Thread.currentThread().getName());
                subscriber.onNext(1);
                subscriber.onCompleted();
            }
        });
    }
    private Observable observeOnObserver(){
        return createObserver1()
                .observeOn(Schedulers.trampoline())
                .subscribeOn(Schedulers.newThread());
    }
    private Observable subscribeOnObserver() {
        return createObserver1()
                .subscribeOn(Schedulers.computation())
                .observeOn(Schedulers.immediate());
    }
    private void subscribeOn_observeOn(){
        observeOnObserver().subscribe(new Action1() {
            @Override
            public void call(Integer integer) {
                log("ObserveOn: "+ Thread.currentThread().getName());
            }
        });
        subscribeOnObserver().subscribe(new Action1() {
            @Override
            public void call(Integer integer) {
                log("subscribeOn: "+ Thread.currentThread().getName());
            }
        });
    }
结果:
on subscribe: RxNewThreadScheduler-1
ObserveOn: RxNewThreadScheduler-1
on subscribe: RxComputationScheduler-1
subscribeOn: RxComputationScheduler-1

3.6.5 timeInterval 和timeStamp

timeInterval 会拦截源Observable发送出来的数据,将其封装为一个TimeInterval对象,TimeInterval对象内部包含Observable发送的原始数据,以及发送当前数据的发送上一个数据的时间间隔。对于第一个发送的数据,其时间间隔为订阅后到首次发送数据之间的时间间隔。

timeStamp同样会将每个数据项重新包装成一个TimeStamp对象,TimeStamp对象内包含了原始数据和一个时间戳,这个时间戳标明了每次数据发送的时间。


    /**
     * timeInterval && timeStamp
     */
    private void timeInterval_TimeStamp(){
        Observable.interval(1, TimeUnit.SECONDS, Schedulers.trampoline()).take(3).timeInterval()
                .subscribe(new Action1>() {
                    @Override
                    public void call(TimeInterval longTimeInterval) {
                        log("timeInterval: "+ longTimeInterval.getValue() + "-" + longTimeInterval.getIntervalInMilliseconds());
                    }
                });
        Observable.interval(1, TimeUnit.SECONDS, Schedulers.trampoline()).take(3).timestamp()
                .subscribe(new Action1>() {
                    @Override
                    public void call(Timestamped longTimestamped) {
                        log("timeStamp: "+ longTimestamped.getValue() + "-" + longTimestamped.getTimestampMillis());
                    }
                });
    }

订阅后的输出结果如下, 可以看到timeInterval操作符将数据封装成了timeInterval对象,可以通过getValue和getIntervalInMilliseconds方法获取到数据和间隔的时间,由于误差存在,间隔的时间在1000毫秒左右浮动;而TimeStamp将数据封装成了timeStamped的对象,可以通过getValue和getTimestampMillis方法获取到数据和封装进去的时间戳。

timeInterval: 0-1011
timeInterval: 1-998
timeInterval: 2-998
timeStamp: 0-1556694232493
timeStamp: 1-1556694233492
timeStamp: 2-1556694234493

***如上, interval这个操作符终于执行成功 ,原因是添加了指定线程Schedulers.trampoline()
官网原因

When you use the default scheduler (Schedulers.computation()) the observable emits on another thread. If your program exits just after the subscribe then the observable is not given a chance to run. Put in a long sleep just after the subscribe() call and you will see it working.

3.6.6 timeout

timeout操作符给Observable加上超时时间,每发送一个数据后就重置计时器,当超过预定的时间还没有发送下一个数据时,就抛出一个超时的异常。

RxJava将timeout实现为很多不同功能的操作符。可以在超时的时候发出一个错误事件;也可以在超时的时候使用另一个Observable代替当前的Observable来继续发送数据。

/**
     * timeout
     */
    private Observable createTimeoutObserver(){
        return Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber subscriber) {
                for(int i=0; i<=3; i++){
                    try{
                        Thread.sleep(i*100);
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    subscriber.onNext(i);
                }
                subscriber.onCompleted();
            }
        });
    }
    private void timeoutTest(){
        createTimeoutObserver().timeout(200, TimeUnit.MILLISECONDS)
                .subscribe(new Subscriber() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        log(e.toString());
                    }

                    @Override
                    public void onNext(Integer integer) {
                        log("timeout: "+ integer);
                    }
                });

        createTimeoutObserver().timeout(200, TimeUnit.MILLISECONDS, Observable.just(5,6))
                .subscribe(new Action1() {
                    @Override
                    public void call(Integer integer) {
                        log(integer);
                    }
                });
    }

订阅结果如下,可看到第一个Observable发送两个数据后出现超时并发送出了错误事件;而第二个Observable在发送两个数据出现超时后,使用了另一个Observable来继续发送数据

timeout: 0
timeout: 1
timeout: 2
java.util.concurrent.TimeoutException
0
1
2
5
6

3.6.7 using

using操作符可创建一个在Observable生命周期内存活的资源,也可以这样理解:我们创建一个资源并使用它,用一个Observable来限制这个资源的使用时间,当这个Observable终止的时候,这个资源就会被销毁。

using需要使用3个参数,分别是:
1.创建这个一次性资源的函数
2.创建Observable的函数
3.释放资源的函数

定义一个Animal类, 在类的构造方法里我们使用interval操作符创建一个Observable对象并将其进行订阅,然后提供一个release方法来反订阅这个Observable。

private class Animal{
        Subscriber subscriber = new Subscriber() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {
                log("animal eat");
            }
        };
        public Animal(){
            log("create animal");
            Observable.interval(1000, TimeUnit.MILLISECONDS).subscribe(subscriber);
        }
        public void release(){
            log("animal released");
            subscriber.unsubscribe();
        }
    }

Animal类创建好了之后,使用using操作符创建一个Animal对象, 并使用timer操作符创建一个5秒控制Observable, 它在5秒后会调用Animal对象的release方法,也就是说这个Animal对象最多只能存在5秒,最后对其进行订阅。

private Observable usingObservable(){
        return Observable.using(new Func0() {
            @Override
            public Animal call() {
                return new Animal();
            }
        }, new Func1>() {
            @Override
            public Observable call(Animal animal) {
                return Observable.timer(5000, TimeUnit.MILLISECONDS, Schedulers.trampoline());
            }
        }, new Action1() {
            @Override
            public void call(Animal animal) {
                animal.release();
            }
        });
    }
    private void usingTest(){
        Subscriber subscriber = new Subscriber() {
            @Override
            public void onCompleted() {
                log("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                log("onError" + e.toString());
            }

            @Override
            public void onNext(Object o) {
                log("onNext: " + o);
            }
        };
        usingObservable().subscribe(subscriber);
    }

结果如下,可以看到我们创建一个Animal对象后,Animal内部会注册一个Observable对象, 并且每秒都会输出一个animal eat , 但是在5秒后会调用Animal的release方法, 从而对Animal内部的Observable对象进行反订阅。

create animal
animal eat
animal eat
animal eat
animal eat
animal eat
onNext: 0
onCompleted
animal released

你可能感兴趣的:(RxJava基础六-辅助操作符)