Rxjava2 combineLatest combineLatestDelayError

322 阅读5分钟

combineLatest

combineLatest操作符的作用是组合发射的数据,通过 Func 类来组装多个 Observable 发射的数据, 等到最后一个 Observable 发射数据了, 然后把所有发射的数据交给Fun进行组合, 然后把组合后的数据发射出去。

        Observable observable1 = Observable.just(1);
        Observable observable2 = Observable.just(2);
        Observable observable3 = Observable.just(3);
        Observable.combineLatest(observable1, observable2, observable3, new Function3<Integer, Integer, Integer, String>() {
            @NotNull
            @Override
            public String apply(@NotNull Integer integer, @NotNull Integer integer2, @NotNull Integer integer3) throws Exception {
                return (integer + integer2 +integer3)+ "";
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(@NotNull Disposable d) {
                System.out.println("onSubscribe");
            }

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

            @Override
            public void onError(@NotNull Throwable e) {
                System.out.println(e.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
        });

输出

onSubscribe
onNext 6
onComplete

看看源码

   public static <T1, T2, T3, R> Observable<R> combineLatest(
           ...
        return combineLatest(Functions.toFunction(combiner), bufferSize(), source1, source2, source3);
    }

Functions.toFunction(combiner)的作用是把combiner对象转换成Function对象,将T1, T2, T3转换成结果R

   public static <T1, T2, T3, R> Function<Object[], R> toFunction(final Function3<T1, T2, T3, R> f) {
        ...
        return new Array3Func<T1, T2, T3, R>(f);
    }
    static final class Array3Func<T1, T2, T3, R> implements Function<Object[], R> {
        final Function3<T1, T2, T3, R> f;

        Array3Func(Function3<T1, T2, T3, R> f) {
            this.f = f;
        }

        @SuppressWarnings("unchecked")
        @Override
        public R apply(Object[] a) throws Exception {
            if (a.length != 3) {
                throw new IllegalArgumentException("Array of size 3 expected but got " + a.length);
            }
            return f.apply((T1)a[0], (T2)a[1], (T3)a[2]);
        }
    }
  public static <T, R> Observable<R> combineLatest(Function<? super Object[], ? extends R> combiner, int bufferSize, ObservableSource<? extends T>... sources) {
        return combineLatest(sources, combiner, bufferSize);
    }
   public static <T, R> Observable<R> combineLatest(ObservableSource<? extends T>[] sources,
            Function<? super Object[], ? extends R> combiner, int bufferSize) {
       ...
        int s = bufferSize << 1;
        return RxJavaPlugins.onAssembly(new ObservableCombineLatest<T, R>(sources, null, combiner, s, false));
    }

转换成ObservableCombineLatest对象,delayError 顾名思义,当出现错误时,是否会延迟onError的执行。

为什么会出现这样的情况,因为消费的方法均是在Scheduler中执行的,因此会有生产和消费速率不一致的情形。那么当出现错误时,可能队列里还有数据未传递给下游,因此delayError这个参数就是为了解决这个问题 。delayEror默认为false, 当出现错误时会直接越过未消费的队列中的数据,在下游处理完当前的数据后会立即执行onError。

如果为true则会保持和上游一致的顺序向下游调度onNext,最后执行onError。后面会分析。 bufferSize是队列SpscLinkedArrayQueue的长度,长度最小是8。

public final class ObservableCombineLatest<T, R> extends Observable<R> {
    final ObservableSource<? extends T>[] sources;
    final Iterable<? extends ObservableSource<? extends T>> sourcesIterable;
    final Function<? super Object[], ? extends R> combiner;
    final int bufferSize;
    final boolean delayError;

    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;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void subscribeActual(Observer<? super R> observer) {
        ObservableSource<? extends T>[] sources = this.sources;
        int count = 0;
        ...

        LatestCoordinator<T, R> lc = new LatestCoordinator<T, R>(observer, combiner, count, bufferSize, delayError);
        lc.subscribe(sources);
    }

LatestCoordinator构造函数里创建了CombinerObserver数组。

  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);
        }

sources[i].subscribe(as[i]);用来订阅CombinerObserver,数据经过这个对象,然后交给 LatestCoordinator处理。 数据本来可以直接发送给观察者。

经过LatestCoordinator的数据处理,将数据组合后重新发送给观察者。

   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]);
            }
        }
static final class CombinerObserver<T, R> extends AtomicReference<Disposable> implements Observer<T> {
        private static final long serialVersionUID = -4823716997131257941L;

        final LatestCoordinator<T, R> parent;

        final int index;

        CombinerObserver(LatestCoordinator<T, R> parent, int index) {
            this.parent = parent;
            this.index = index;
        }

        @Override
        public void onSubscribe(Disposable d) {
            DisposableHelper.setOnce(this, d);
        }

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

        @Override
        public void onError(Throwable t) {
            parent.innerError(index, t);
        }

        @Override
        public void onComplete() {
            parent.innerComplete(index);
        }

        public void dispose() {
            DisposableHelper.dispose(this);
        }
    }

LatestCoordinator内部的innerNext的方法中,latest表示最新的数据,当发送的数据量和被观察者一样时,就可以把数据放到队列中,drain的含义时排空,就是把数据打包发送给下游

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();
            }
        }

done表示所有生产者都已经把数据发送完成或者还没有发送就出错。因为getAndIncrement的意思是原子加1,并且返回原来的值,第一次进入drain函数,getAndIncrement()返回的结果就是0,现在原子变量已经变成了1,阻止其他线程再次调用。addAndGet表示原子加上一个值,并且返回更新后的值, 第一层的for循环持续更新原子变量,一直把值更新到原来的0,第二层的for循环是要把数据给排空,排出数据的过程中,很可能出现生产者出错,有2种策略,要么把数据排空后调用error,要么不要queue里的数据了,直接调用error,这就要用delayError控制了,为true时就是第一种,为false时就是第二种。

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;
                    }

		    //delayError 默认是fasle,表示一旦出错,队列里还有没有发送给观察者的数据就要被遗弃掉了
                    if (!delayError && errors.get() != null) {
                        cancelSources();
                        clear(q);
                        a.onError(errors.terminate());
                        return;
                    }

                    boolean d = done;
                    Object[] s = q.poll(); //弹出数据
                    boolean empty = s == null;
                    
                    //保证数据被排空
                    //没有出错,就是onComplete
                    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;
                }
            }
        }

latest[index] == null;表示生产者还没有发送数据。

   void innerError(int index, Throwable ex) {
            if (errors.addThrowable(ex)) {
                boolean cancelOthers = true;
                if (delayError) {
                   //delayError为true时,
                    synchronized (this) {
                        Object[] latest = this.latest;
                        if (latest == null) {
                            return;
                        }
			//还没有发送数据,就已经出错,后面的数据也就没有必要发送了。
                        cancelOthers = latest[index] == null;
                        if (cancelOthers || ++complete == latest.length) {
                            done = true;
                        }
                    }
                }
                if (cancelOthers) {
                    cancelSources();
                }
                drain();
            } else {
                RxJavaPlugins.onError(ex);
            }
        }

Android中经常用它提交表单,当用户名和密码都被填写后,登录按钮才能使用。

disposables += Observable.combineLatest(
        view.onNameChanged(), view.onEmailChanged(), ::AccountInfo)
        .subscribe { accountInfo ->   
            view.setNextStepButtonEnabled(accountInfo.isValid())
        }

combineLatestDelayError

combineLatestDelayError就是会设置delayError为true。

Observable o1 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NotNull ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        });

        Observable o2 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NotNull ObservableEmitter<Integer> emitter) throws Exception {
                //emitter.onError(new Exception("我死了~"));  会调用onError
                emitter.onNext(4);
                emitter.onNext(5);
                emitter.onError(new Exception("我死了~"));  //不会调用onError,事件流停止
                emitter.onNext(6);
            }
        });


        Observable.combineLatestDelayError(new Function<Object[], String>() {
            @Override
            public String apply(@NotNull Object[] objects) throws Exception {
                StringBuilder sb = new StringBuilder();
                Arrays.stream(objects).forEach(o -> sb.append(o).append("-"));
                return sb.toString();
            }
        }, 2, o1, o2).subscribe(new Observer() {
            @Override
            public void onSubscribe(@NotNull Disposable d) {
                System.out.println("onSubscribe");
            }

            @Override
            public void onNext(@NotNull Object o) {
                System.out.println("onNext " + o);
            }

            @Override
            public void onError(@NotNull Throwable e) {
                System.out.println("onError " + e.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
        });