实验
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}; 因为它们的内部数据结构的使用不同。