Zip
Zip通过一个函数将多个Observable发送的事件结合到一起,然后发送这些组合到一起的事件. 它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据。请看下面的图解。
上游有2支水管,分别从两根水管里各取出一个事件来进行组合, 并且一个事件只能被使用一次, 组合的顺序是严格按照事件发送的顺利进行的。
最终下游收到的事件数量是和上游中发送事件最少的那一根水管的事件数量相同. 这个也很好理解, 因为是从每一根水管 里取一个事件来进行合并, 最少的那个肯定就最先取完 , 这个时候其他的水管尽管还有事件 , 但是已经没有足够的事件来组合了, 因此下游就不会收到剩余的事件了。
Show me the code
//上游的水管“A”
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
Log.d(TAG, "emit 1");
e.onNext(1);
Thread.sleep(100);
Log.d(TAG, "emit 2");
e.onNext(2);
Thread.sleep(100);
Log.d(TAG, "emit 3");
e.onNext(3);
Thread.sleep(100);
Log.d(TAG, "emit 4");
e.onNext(4);
Thread.sleep(100);
Log.d(TAG, "emit complete1");
e.onComplete();
}
}).subscribeOn(Schedulers.newThread());
//上游的水管“B”
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
Log.d(TAG, "emit one");
e.onNext("one");
Thread.sleep(100);
Log.d(TAG, "emit two");
e.onNext("two");
Thread.sleep(100);
Log.d(TAG, "emit three");
e.onNext("three");
Thread.sleep(100);
Log.d(TAG, "emit complete2");
e.onComplete();
}
}).subscribeOn(Schedulers.newThread());
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String s) throws Exception {
return integer + " = " + s;
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe");
}
@Override
public void onNext(String value) {
Log.d(TAG, "onNext :" + value);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError :" + e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
05-21 06:03:16.100 19473-19473/com.example.administrator.testdemo D/tag: onSubscribe
05-21 06:03:16.104 19473-19503/com.example.administrator.testdemo D/tag: emit 1
05-21 06:03:16.105 19473-19504/com.example.administrator.testdemo D/tag: emit one
05-21 06:03:16.105 19473-19504/com.example.administrator.testdemo D/tag: onNext :1 = one
05-21 06:03:16.205 19473-19504/com.example.administrator.testdemo D/tag: emit two
05-21 06:03:16.205 19473-19503/com.example.administrator.testdemo D/tag: emit 2
05-21 06:03:16.205 19473-19503/com.example.administrator.testdemo D/tag: onNext :2 = two
05-21 06:03:16.306 19473-19504/com.example.administrator.testdemo D/tag: emit three
05-21 06:03:16.307 19473-19503/com.example.administrator.testdemo D/tag: emit 3
05-21 06:03:16.307 19473-19503/com.example.administrator.testdemo D/tag: onNext :3 = three
05-21 06:03:16.408 19473-19504/com.example.administrator.testdemo D/tag: emit complete2
05-21 06:03:16.408 19473-19503/com.example.administrator.testdemo D/tag: emit 4
05-21 06:03:16.408 19473-19504/com.example.administrator.testdemo D/tag: onComplete
注意:
1、发送的2组事件都需要处于子线程,并且每发送一个事件之后加入一定时间的延时,不然会出现以下的结果:
05-21 06:09:27.572 25819-25819/com.example.administrator.testdemo D/tag: onSubscribe
05-21 06:09:27.576 25819-25849/com.example.administrator.testdemo D/tag: emit 1
05-21 06:09:27.576 25819-25849/com.example.administrator.testdemo D/tag: emit 2
05-21 06:09:27.576 25819-25849/com.example.administrator.testdemo D/tag: emit 3
05-21 06:09:27.576 25819-25849/com.example.administrator.testdemo D/tag: emit 4
05-21 06:09:27.577 25819-25849/com.example.administrator.testdemo D/tag: emit complete1
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: emit one
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: onNext :1 = one
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: emit two
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: onNext :2 = two
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: emit three
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: onNext :3 = three
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: emit complete2
05-21 06:09:27.578 25819-25850/com.example.administrator.testdemo D/tag: onComplete
2、下游收到的事件数量是和上游中发送事件最少的那一根水管的事件数量相同
思维延伸
我们说到Zip可以将多个上游发送的事件组合起来发送给下游, 那大家有没有想过一个问题, 如果其中一个水管A发送事件特别快, 而另一个水管B 发送事件特别慢的情况,那么会发生什么情况呢…
请看代码:
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for (int i = 0; ; i++) {
//无限循环
e.onNext(i);
}
}
}).subscribeOn(Schedulers.newThread());
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
Log.d(TAG, "emit one");
}
}).subscribeOn(Schedulers.newThread());
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String s) throws Exception {
return integer + " = " + s;
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, "accept:" + s);
}
});
请看效果:
我的天,翻车了:使用的内存在短时间内急剧上涨,瞬间OOM。
那是不是只有zip会这样,我们一起来看下最简单的:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for (int i = 0; ; i++) {
//无限循环
e.onNext(i);
}
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "accept:" + integer);
}
});
跟上面的例子一样,内存也是爆掉了。
上游的每一个事件,下游都要一一处理,而且上游在短时间发送太多的事件,让下游来不及处理就造成了事件的阻塞,那么我们是否可以用一些自己的方法来解决这种阻塞呢?
首先,我们分析阻塞形成的原因,无非是因为下面的原因啊:
- 上游的水流过快(上游发送事件过快)
- 上游水流量过大(上游发送事件过多)
好吧,首先我们用第一种办法试下,让上游发送事件的速度慢点
//控制发送速度,减少内存消耗
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for (int i = 0; ; i++) {
//无限循环
e.onNext(i);
Thread.sleep(1000);
}
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "accept:" + integer);
}
});
方案一,成功!
那么,试试第二种方法,下游少接收点事件:
//下游少接收点事件
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for (int i = 0; ; i++) {
//无限循环
e.onNext(i);
}
}
}).filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
return integer%100==0;
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "accept:" + integer);
}
});
内存上看起来还不错,但是CPU的使用率很恐怖。
上面唠唠叨叨说了那么多,基本上也给大家阐明了阻塞形成的原因和解决阻塞的方法,基本策略就是减少发送事件的频率和减少发送事件的数量。
But…
我们手动让上游发送事件的速度满下来貌似是不可取的,你想让上游的速度十多快呢?上游需要等多久呢?
And…
我们依旧无法知道下游处理事件的能力,无法很好地处理阻塞的事件。
So….
官方是怎样解决的呢?
期待我们下次再见,将带来Flowable的学习,see u :)