RxJava2操作符内部流程理解-Repeat

了解本章内容请最好是先了解
RxJava2操作符内部流程理解-概念
repeat操作符就是指的"重复",当上游发送数据结束了之后,在这个操作符内部会再次往上游订阅数据,再次触发subscribeActual 方法。这样就可以再次从头到尾的获得一遍之前的全部数据,根据传入的参数,repeat 可以多次重复。

示例代码

        Observable.range(0, 10).repeat(5).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                print("s:" + integer);
            }
        });

按照我们的思路,肯定得进入repeat操作符里面去看看
step1

    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final Observable<T> repeat(long times) {
        if (times < 0) {
            throw new IllegalArgumentException("times >= 0 required but it was " + times);
        }
        if (times == 0) {
            return empty();
        }
        return RxJavaPlugins.onAssembly(new ObservableRepeat<T>(this, times));
    }

好的,这里进行一系列的参数检查之后,来到了我们的老套路,创建一个 ObservableRepeat,继续
step2

    @Override
    public void subscribeActual(Observer<? super T> observer) {
        SequentialDisposable sd = new SequentialDisposable();
        observer.onSubscribe(sd);

        RepeatObserver<T> rs = new RepeatObserver<T>(observer, count != Long.MAX_VALUE ? count - 1 : Long.MAX_VALUE, sd, source);
        rs.subscribeNext();
    }

来到我们熟知的方法 subscribeActual,这里也是创建一个 RepeatObserver,我们注意到下面的这个名字叫 subscribeNext 的方法,它应该也是订阅,但是方法名让我们更加留意了。
step3

        void subscribeNext() {
            if (getAndIncrement() == 0) {
                int missed = 1;
                for (;;) {
                    if (sd.isDisposed()) {
                        return;
                    }
                    source.subscribe(this);

                    missed = addAndGet(-missed);
                    if (missed == 0) {
                        break;
                    }
                }
            }
        }

这个方法内部使用了父类是原子类的特点控制变量来保证线程安全,大概流程是:当变量为0的时候,变量加1,然后执行订阅上游的操作,订阅完成之后,再次变量减为0.这样空值了订阅这个操作不会出现多线程问题。
这里我们猜想就是repeat的关键所在。
step4
我们查看 RepeatObserver 这个类,我们知道这个类是用来获取上游onNext传下来的数据的,以往分析都会进入onNext 方法里面一探究竟,但是我们发现这里的onNext居然没有做任何事情,直接往下游传递了数据

        @Override
        public void onNext(T t) {
            downstream.onNext(t);
        }

使用这个操作的时候我们知道,它是每次等上游发送完毕了之后才开始重复的,所以我想它一定是在onComplete方法里面处理的,果然。

        @Override
        public void onComplete() {
            long r = remaining;
            if (r != Long.MAX_VALUE) {
                remaining = r - 1;
            }
            if (r != 0L) {
                subscribeNext();
            } else {
                downstream.onComplete();
            }
        }

相信来到这里大家就会很明了了,remaining,顾名思义就是剩余量的意思,重复过程中还剩多少次,当剩余次数不为0的时候回调用我们之前看到的 subscribeNext() 再次订阅触发上游的数据事件,最终重复次数达到的时候,触发下游的 onComplet() ,完成。

同理我们可以去查看 repeatUntil(),repeatWhen(),这两个操作符,大同小异,只是传入了一个 BooleanSupplier,或者 Function来做条件判断。
repeatWhen() 有一点复杂是因为,它提供一个可观察者对象,这个对象会在上游事件onComplete的时候触发一下自己的onNext,也就是通知上游事件完成了,然后在apply 里面返回一个可观察者对象,这个对象发送数据的时候会触发重复订阅的操作,由于只是关心发送数据这件事情,而不是发送数据的内容,所以内部并没有用到传入的数据,所以这里写了一个object对象来通用。

        Observable.range(0, 10).repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(Observable<Object> signaller) throws Exception {
//                signaller 是内部的,上游结束之后会触发这个signaller
                return signaller.flatMap(new Function<Object, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Object o) throws Exception {
                        return Observable.timer(3, TimeUnit.SECONDS);
                    }
                });
            }
        }).blockingSubscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                print("i:" + integer);
            }
        });

总结

这个操作很简单,逻辑也很清晰,但是有一点值得思考的是它是依靠再次订阅触发 subscribeActual() 来达到发送数据的效果的,这对justfromrangcreate 这些操作符有效果,因为他们都在 subscribeActual() 方法里面直接触发了数据发送。
但是对PublishSubject 这样特殊的类就没效果了,因为它是靠直接onNext()发送数据的,并不是在我们期待的 subscribeActual() 里面。请看下面代码

 PublishSubject<String> subject = PublishSubject.create();

        subject.repeat(6).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                System.out.println();
            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
        });
        subject.onNext("hello1");
        subject.onNext("hello2");
        subject.onNext("hello3");
        subject.onNext("hello4");
        subject.onNext("hello5");
        subject.onNext("hello6");
        subject.onNext("hello7");

运行结果:

hello1
hello2
hello3
hello4
hello5
hello6
hello7

并不是我们想要的那样。这需要注意。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值