Rxjava 源码分析Zip与combinelatest区别

实验

  public static void main(String[] args) {
        testZip();
        testComb();
    }
    public static void testZip() {
        Observable<Integer> obs1 = Observable.just(1, 2, 3, 4, 5, 6, 7);
        Observable<Integer> obs2 = Observable.just(4, 5, 6, 7, 8, 9, 10);
        Observable<Integer> obs3 = Observable.just(5, 6, 7);
        Disposable subscribe = Observable.zip(obs1, obs2, obs3, (integer, integer2, integer3) -> {
            System.out.println("zip apply" + "first:" + integer + "  second:" + integer2 + "  third:" + integer3);
            return integer + integer2 + integer3;
        }).subscribe(integer -> System.out.println("zip accept" + "result:" + integer), new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                System.out.println("zip error" + throwable.getMessage());
            }
        });
    }

    public static void testComb() {
        Observable<Integer> obs1 = Observable.just(1, 2, 3, 4, 5, 6, 7);
        Observable<Integer> obs2 = Observable.just(4, 5, 6, 7, 8, 9, 10);
        Observable<Integer> obs3 = Observable.just(5, 6, 7);
        Disposable subscribe = Observable.combineLatest(obs1, obs2, obs3, new Function3<Integer, Integer, Integer, Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2, Integer integer3) {
                System.out.println("combineLatest apply" + "first:" + integer + "  second:" + integer2 + "  third:" + integer3);
                return integer + integer2 + integer3;
            }
        }).subscribe(integer -> System.out.println("combineLatest accept" + "result:" + integer), new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                System.out.println("combineLatest error" + throwable.getMessage());
            }
        });
    }

实验结果
在这里插入图片描述
结果分析
从结果上来看,zip和combineLatest分别都是发射了三次数据。
zip {1,4,5} {2,5,6} {3,6,7};
combineLatest {7,10,5} {7,10,6} {7,10,7}

源码分析
1.我们先从combinlatest分析。

 public static <T1, T2, T3, R> Observable<R> combineLatest(
            ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2,
            ObservableSource<? extends T3> source3,
            Function3<? super T1, ? super T2, ? super T3, ? extends R> combiner) {
		...
       return RxJavaPlugins.onAssembly(new ObservableCombineLatest<T, R>(sources, null, combiner, s, false));
    }

Observable的combineLatest会通过ObservableCombineLatest返回一个Observable,
我们看一下ObservableCombineLatest的构造方法。

  public ObservableCombineLatest(ObservableSource<? extends T>[] sources,
            Iterable<? extends ObservableSource<? extends T>> sourcesIterable,
            Function<? super Object[], ? extends R> combiner, int bufferSize,
            boolean delayError) {
        this.sources = sources;
        this.sourcesIterable = sourcesIterable;
        this.combiner = combiner;
        this.bufferSize = bufferSize;
        this.delayError = delayError;
    }

类图
在这里插入图片描述
这个类的结构很简单,说一下这个subscribeActual,这个是在Observable的subscribe(Observer) 方法中调用的,也就是说,当数据源订阅时,会调用此方法。看一下这个方法内部干了什么

public void subscribeActual(Observer<? super R> observer) {
        ObservableSource<? extends T>[] sources = this.sources;
        int count = 0;
        if (sources == null) {
           ...
        } else {
            count = sources.length;
        }
		...
        LatestCoordinator<T, R> lc = new LatestCoordinator<T, R>(observer, combiner, count, bufferSize, delayError);
        lc.subscribe(sources);
    }

可以看到创建了一个LatestCoordinator,然后把数据源通过lc.subscribe(sources)传递进去。
我们继续看一下LatestCoordinator,构造方法

LatestCoordinator(Observer<? super R> actual,
                Function<? super Object[], ? extends R> combiner,
                int count, int bufferSize, boolean delayError) {
            this.downstream = actual;
            this.combiner = combiner;
            this.delayError = delayError;
            this.latest = new Object[count];
            CombinerObserver<T, R>[] as = new CombinerObserver[count];
            for (int i = 0; i < count; i++) {
                as[i] = new CombinerObserver<T, R>(this, i);
            }
            this.observers = as;
            this.queue = new SpscLinkedArrayQueue<Object[]>(bufferSize);
        }

在这里插入图片描述

donwnstream,我们外部实际的订阅者。combiner,我们写的apply函数;指得注意的就是latest,as与queue了。我们下面会详细讲。其次看它的subscribe方法

 public void subscribe(ObservableSource<? extends T>[] sources) {
            Observer<T>[] as = observers;
            int len = as.length;
            downstream.onSubscribe(this);
            for (int i = 0; i < len; i++) {
                if (done || cancelled) {
                    return;
                }
                sources[i].subscribe(as[i]);
            }
        }

一个for循环订阅我们构造方法里创建的observers.这里可以看到,这个时候我们的数据源被订阅了,开始发射数据。然后我们看一下构造方法里创建的CombinerObserver.这个CombinerObserver的onNext方法

  public void onNext(T t) {
            parent.innerNext(index, t);
        }

调用parent的innerNext()即ObservableCombineLatest的innerNext

void innerNext(int index, T item) {
            boolean shouldDrain = false;
            synchronized (this) {
                Object[] latest = this.latest;
                if (latest == null) {
                    return;
                }
                Object o = latest[index];
                int a = active;
                if (o == null) {
                    active = ++a;
                }
                latest[index] = item;
                if (a == latest.length) {
                    queue.offer(latest.clone());
                    shouldDrain = true;
                }
            }
            if (shouldDrain) {
                drain();
            }
        }

这段代码是重点,我们知道在LatestCoordinator的subscribe方法中有创建了多个observers,也就是说,每一个obserser的onNext方法都会走parent.innerNext,也就是说每一次发射数据此方法就会调用。
这里获取latest数组,latest数组是LatestCoordinator构造方法的时候创建的一个,与Observable数量大小相等的一个数组,本例中大小是3.可以看到每次的onNext的结果都会保存到对应的数组里。当三个Observable最后一个Obserable发射数据的时候,a==latest.Length条件成立,将结果放到quque里。
之后shouldDrain为true,调用drain方法。我们看一下drain方法

void drain() {
            if (getAndIncrement() != 0) {
                return;
            }

            final SpscLinkedArrayQueue<Object[]> q = queue;
            final Observer<? super R> a = downstream;
            final boolean delayError = this.delayError;

            int missed = 1;
            for (;;) {

                for (;;) {
                    if (cancelled) {
                        clear(q);
                        return;
                    }

                    if (!delayError && errors.get() != null) {
                        cancelSources();
                        clear(q);
                        a.onError(errors.terminate());
                        return;
                    }

                    boolean d = done;
                    Object[] s = q.poll();
                    boolean empty = s == null;

                    if (d && empty) {
                        clear(q);
                        Throwable ex = errors.terminate();
                        if (ex == null) {
                            a.onComplete();
                        } else {
                            a.onError(ex);
                        }
                        return;
                    }

                    if (empty) {
                        break;
                    }

                    R v;

                    try {
                        v = ObjectHelper.requireNonNull(combiner.apply(s), "The combiner returned a null value");
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        errors.addThrowable(ex);
                        cancelSources();
                        clear(q);
                        ex = errors.terminate();
                        a.onError(ex);
                        return;
                    }

                    a.onNext(v);
                }

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

关键部分就是quque的数据出队,调用combiner.apply方法,此方法就是我们在实验中合并Observables的Function.到这里就很明白了。也就是说本例中三个observable是顺序执行的,不断发射数据,前两个Obserable发射完数据,并不能使shouldDrain为true,当第三个Obserable发射的时候,shouldDrain为true,则第三个obserable发射的数据,与之前两个Obserable发射的数据的最后一个保存在latest数组里的对应index下面的数据结合,调用apply回调。

Zip

zip操作符与CombineLatest很相似,基本一致,区别在于,每个订阅者ZipObserver的内部都有一个queue,而combineLatest的queue就一个在LatestCoordinator中。

        ZipObserver(ZipCoordinator<T, R> parent, int bufferSize) {
            this.parent = parent;
            this.queue = new SpscLinkedArrayQueue<T>(bufferSize);
        }

ZipObserver在调用onNext的时候每次都会直接将自己的数据保存在自己的队列中,然后调用drain方法

        @Override
        public void onNext(T t) {
            queue.offer(t);
            parent.drain();
        }

在drain方法中两者也是有却别的,

public void drain() {
            if (getAndIncrement() != 0) {
                return;
            }

            int missing = 1;

            final ZipObserver<T, R>[] zs = observers;
            final Observer<? super R> a = downstream;
            final T[] os = row;
            final boolean delayError = this.delayError;

            for (;;) {

                for (;;) {
                    int i = 0;
                    int emptyCount = 0;
                    for (ZipObserver<T, R> z : zs) {
                        if (os[i] == null) {
                            boolean d = z.done;
                            T v = z.queue.poll();
                            boolean empty = v == null;

                            if (checkTerminated(d, empty, a, delayError, z)) {
                                return;
                            }
                            if (!empty) {
                                os[i] = v;
                            } else {
                                emptyCount++;
                            }
                        } else {
                            if (z.done && !delayError) {
                                Throwable ex = z.error;
                                if (ex != null) {
                                    cancelled = true;
                                    cancel();
                                    a.onError(ex);
                                    return;
                                }
                            }
                        }
                        i++;
                    }

                    if (emptyCount != 0) {
                        break;
                    }

                    R v;
                    try {
                        v = ObjectHelper.requireNonNull(zipper.apply(os.clone()), "The zipper returned a null value");
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        cancel();
                        a.onError(ex);
                        return;
                    }

                    a.onNext(v);

                    Arrays.fill(os, null);
                }

                missing = addAndGet(-missing);
                if (missing == 0) {
                    return;
                }
            }
        }

关键是 for (ZipObserver<T, R> z : zs)这个for循环,它会遍历Observer,把每个Observer队列的数据出队与其他Observer队列的数据组合成一个数组os里,然后把os通过apply方法回调给我们。这里是它们两个的本质却别,也是为什么我们的实验结果是zip {1,4,5} {2,5,6} {3,6,7}; 因为它们的内部数据结构的使用不同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值