RxJava 1.x 笔记:组合型操作符
最近去检查眼睛,发现度数又涨了,唉,各位猿多注意保护自己的眼睛吧!
前面学了 RxJava 的三种关键操作符:
读完本文你将了解第四种(组合型操作符):
组合型操作符
组合型操作符即处理多个 Observable 数据源,在处理后将它们合并成一个 Observable。
Zip
Zip
操作符的作用是:通过一个特定的函数组合多个 Observable 发射的数据,然后发射每个组合的结果。
Zip
操作符对你选中的多个 Observable 发射的数据按顺序应用一个函数,然后返回一个 Observable,这个 Observable 发射函数的返回结果。
Zip
操作符对发射的数据的顺序很严格,如上图所示,它发射的第一个数据一定是 Observable A 发射的第一个数据和 Observable B 发射的第一个数据经过组合的结果;发射的第二个数据也一定是 A 发射的第二个数据和 B 发个的第二个数据的组合结果;一次类推,直到元素最少的 Observable 发射完元素。
RxJava 中对应的实现是 zip
和 zipWith
。
zip
RxJava 中,zip()
的重载方法有 11 种:
前 2 个支持以 Iterable
或者数组的形式传入多个 Observable,后面 9 个分别支持从 1 到 9 个 Observable 作为参数,所有方法的最后一个参数是一个函数,它接收各个 Observable 按顺序发出的数据,然后对它们进行一个操作,将操作的结果发射出去。
public static <T1, T2, R> Observable<R> zip(Observable<? extends T1> o1, Observable<? extends T2> o2, final Func2<? super T1, ? super T2, ? extends R> zipFunction) {
return just(new Observable<?>[] { o1, o2 }).lift(new OperatorZip<R>(zipFunction));
}
使用例子:
private void zip() {
Observable<String> observableA = Observable.just("A", "B", "C", "d", "E");
Observable<Integer> observableB = Observable.just(1, 2, 3, 4);
Observable
.zip(observableA, observableB, new Func2<String, Integer, String>() {
@Override
public String call(final String s, final Integer integer) {
return s + "_" + integer;
}
})
.subscribe(this.<String>getPrintSubscriber());
}
运行结果:
07-19 14:59:11.219 12254-12254/top.shixinzhang.rxjavademo I/System.out: onNext: A_1
07-19 14:59:11.219 12254-12254/top.shixinzhang.rxjavademo I/System.out: onNext: B_2
07-19 14:59:11.219 12254-12254/top.shixinzhang.rxjavademo I/System.out: onNext: C_3
07-19 14:59:11.219 12254-12254/top.shixinzhang.rxjavademo I/System.out: onNext: d_4
07-19 14:59:11.219 12254-12254/top.shixinzhang.rxjavademo I/System.out: onCompleted
可以看到,zip()
的确按顺序将 observableA 和 observableB 发射的数据组合了起来,然后发射了出去。当元素较少的一个 Observable 发射完后,zip 也就停止发射了。
zipWith
zipWith
也可以组合多个 Observable,不过和 zip
不同的是,zipWith
是非静态方法,它需要一个 Observable 来调用。
zipWith
两种重载:
public final <T2, R> Observable<R> zipWith(Observable<? extends T2> other, Func2<? super T, ? super T2, ? extends R> zipFunction) {
return (Observable<R>)zip(this, other, zipFunction);
}
public final <T2, R> Observable<R> zipWith(Iterable<? extends T2> other, Func2<? super T, ? super T2, ? extends R> zipFunction) {
return lift(new OperatorZipIterable<T, T2, R>(other, zipFunction));
}
第一个方法的参数是一个 Observable,它的作用是将当前 Observable 和参数 Observable 组合;第二个方法的参数是一个 Iterable,它的作用是将当前 Observable 和许多 Observable 组合。
使用例子:
private void zipWith() {
Observable<String> observableA = Observable.just("A", "B", "C", "d", "E");
Observable
.just(1, 2, 3, 4)
.zipWith(observableA, new Func2<Integer, String, String>() {
@Override
public String call(final Integer integer, final String s) {
return integer + ", " + s;
}
})
.subscribe(this.<String>getPrintSubscriber());
}
运行结果:
07-19 16:28:50.969 27717-27717/top.shixinzhang.rxjavademo I/System.out: onNext: 1, A
07-19 16:28:50.969 27717-27717/top.shixinzhang.rxjavademo I/System.out: onNext: 2, B
07-19 16:28:50.969 27717-27717/top.shixinzhang.rxjavademo I/System.out: onNext: 3, C
07-19 16:28:50.969 27717-27717/top.shixinzhang.rxjavademo I/System.out: onNext: 4, d
07-19 16:28:50.969 27717-27717/top.shixinzhang.rxjavademo I/System.out: onCompleted
和 zip
很相似是吧。
CombineLatest
CombineLatest
操作符的作用是:当两个 Observable 中任意一个发射数据时,会结合另外一个 Observable 最近发射的数据进行一些函数操作,然后将操作的结果发射出去。
CombineLatest
和 Zip
有点相似,都是将两个 Observable 发射的数据结合起来,不同的是,每个 Observable 都发射了新元素后, Zip
才进行操作然后发射操作结果;而 CombineLatest
在每个 Observable 都发射一个数据后,只要有一个 Observable 发射数据,CombineLatest
就会进行操作然后发射操作结果。
当任何一个 Observable 发射了新数据,CombineLatest
会将这个新数据与另外的 Observable 之前发射的最新数据进行一个函数操作。
RxJava 中有两种实现:combineLatest
, withLatestFrom
。
combineLatest
RxJava 中的 combineLatest()
有 10 种重载:
不同的地方基本就是接收 Observable 的个数不同。
public static <T1, T2, R> Observable<R> combineLatest(Observable<? extends T1> o1, Observable<? extends T2> o2, Func2<? super T1, ? super T2, ? extends R> combineFunction) {
return (Observable<R>)combineLatest(Arrays.asList(o1, o2), Functions.fromFunc(combineFunction));
}
public static <T, R> Observable<R> combineLatest(List<? extends Observable<? extends T>> sources, FuncN<? extends R> combineFunction) {
return unsafeCreate(new OnSubscribeCombineLatest<T, R>(sources, combineFunction));
}
使用例子:
/***
* 将 A 发射的数据与 B 之前发射最新的数据结合,进行函数操作
*/
private void combineLatest() {
Observable<Long> observableA = Observable.interval(3, TimeUnit.SECONDS);
Observable<Long> observableB = Observable.interval(2, TimeUnit.SECONDS);
Observable
.combineLatest(observableA, observableB, new Func2<Long, Long, String>() {
@Override
public String call(final Long itemA, final Long itemB) {
return "combine result: " + itemA + "/" + itemB;
}
}).subscribe(this.<String>getPrintSubscriber());
}
在上面的代码中我们创建了两个 Observable,发射速率分别为 3 秒和 2 秒。运行结果:
07-24 15:38:53.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 0/0
07-24 15:38:54.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 0/1
07-24 15:38:56.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 1/1
07-24 15:38:56.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 1/2
07-24 15:38:58.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 1/3
07-24 15:38:59.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 2/3
07-24 15:39:00.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 2/4
07-24 15:39:02.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 3/4
07-24 15:39:02.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 3/5
07-24 15:39:04.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 3/6
07-24 15:39:05.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 4/6
07-24 15:39:06.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 4/7
07-24 15:39:08.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 5/7
07-24 15:39:08.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 5/8
07-24 15:39:10.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 5/9
07-24 15:39:11.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 6/9
07-24 15:39:12.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 6/10
07-24 15:39:14.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 7/10
07-24 15:39:14.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 7/11
07-24 15:39:16.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 7/12
07-24 15:39:17.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 8/12
07-24 15:39:18.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 8/13
07-24 15:39:20.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 9/13
07-24 15:39:20.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 9/14
07-24 15:39:22.505 27111-27162/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 9/15
07-24 15:39:23.505 27111-27161/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: combine result: 10/15
可以看到,有元素重复多次,说明一个 Observable 还没发射数据,另一个 Observable 发射数据就会出发 combineLatest
。
默认不在任何调度器上。
withLatestFrom
withLatestFrom
和 combineLatest
很相似,不同之处在于,它不是静态方法,必须通过一个 Observable 对象进行调用。而他的作用就是:只有在这个 Observable 对象发射数据时,才结合其他 Observable 发射的最新数据进行相关的函数操作。
也就是说把组合的主动权都交给了调用对象。
使用例子:
private void withLatestFrom() {
Observable<Long> observableA = Observable.interval(3, TimeUnit.SECONDS);
Observable<Long> observableB = Observable.interval(2, TimeUnit.SECONDS);
observableB.withLatestFrom(observableA, new Func2<Long, Long, String>() {
@Override
public String call(final Long itemA, final Long itemB) {
return "withLatestFrom: " + itemA + "/" + itemB;
}
}).subscribe(this.<String>getPrintSubscriber());
}
运行结果:
07-24 15:56:13.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 1/0
07-24 15:56:15.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 2/1
07-24 15:56:17.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 3/1
07-24 15:56:19.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 4/2
07-24 15:56:21.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 5/3
07-24 15:56:23.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 6/3
07-24 15:56:25.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 7/4
07-24 15:56:27.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 8/5
07-24 15:56:29.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 9/5
07-24 15:56:31.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 10/6
07-24 15:56:33.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 11/7
07-24 15:56:35.775 28434-28450/top.shixinzhang.rxjavademo D/top.shixinzhang.rxjavademo: onNext: withLatestFrom: 12/7
的确如我们所想,只有 observableB 发射数据时,才进行组合操作。
Join
Join
操作符的作用是:在一个 Observable 发射的一条数据的时间窗口内,另外一个 Observable 发射了一条数据,就组合这两条数据。
如上图所示,我们可以给两个 Observable 各自定义它们发射的数据的时间窗口(可以理解为生命周期),在 Observable A 发射一个元素 a 后,在 a 的生命周期内,Observable B 只要发射了数据,就会和 a 组合。如果 A 定义的时间窗口比发射速率久,就会出现 B 发射的数据跟 A 的多个数据组合;反过来也一样,在 B 发射的元素时间窗口内,A 发射数据也会和 B 的元素组合。
Join 的概念不是很容易理解,这个操作符需要多费点心。
RxJava 中的实现有两种:join()
和 groupJoin()
。
join
API 对 join()
的介绍是:
Correlates the items emitted by two Observables based on overlapping durations.
即:根据重叠持续时间将两个 Observable 发出的项关联起来。
join()
方法如下:
public final <TRight, TLeftDuration, TRightDuration, R> Observable<R> join(Observable<TRight> right, Func1<T, Observable<TLeftDuration>> leftDurationSelector,
Func1<TRight, Observable<TRightDuration>> rightDurationSelector,
Func2<T, TRight, R> resultSelector) {
return unsafeCreate(new OnSubscribeJoin<T, TRight, TLeftDuration, TRightDuration, R>(this, right, leftDurationSelector, rightDurationSelector, resultSelector));
}
它接收 4 个参数:
- right:将要和当前 Observable 元素组合的另一个 Observable
- leftDurationSelector:定义当前 Observable 发射元素的时间窗口函数,返回一个 Observable
- rightDurationSelector:定义 right Observable 发射元素的时间窗口函数
- resultSelector:在这个函数中做两个 Observable 元素的组合操作
使用例子:
private void join() {
//产生 0 2 4 6 8
Observable<Long> observableA = Observable.interval(1, TimeUnit.SECONDS)
.map(new Func1<Long, Long>() {
@Override
public Long call(final Long aLong) {
return aLong * 2;
}
})
.take(5);
//产生 0 3 6 9 12
Observable<Long> observableB = Observable.interval(2, TimeUnit.SECONDS)
.map(new Func1<Long, Long>() {
@Override
public Long call(final Long aLong) {
return aLong * 3;
}
})
.take(5);
observableA.join(observableB,
new Func1<Long, Observable<Long>>() { //定义源 Observable 发射数据的时间窗口
@Override
public Observable<Long> call(final Long aLong) {
System.out.println("A:" + aLong);
return Observable.just(aLong).delay(2000 , TimeUnit.MILLISECONDS); //延迟 500 毫秒后发射,即声明周期为 1000毫秒
}
}, new Func1<Long, Observable<Long>>() { //定义第二个 Observable 发射数据的时间窗口
@Override
public Observable<Long> call(final Long aLong) {
System.out.println("B:" + aLong);
return Observable.just(aLong).delay(1000, TimeUnit.MILLISECONDS);
}
}, new Func2<Long, Long, String>() { //组合两个 Observable 发射的数据的函数
@Override
public String call(final Long aLong, final Long aLong2) {
return "join result:" + aLong + "/" + aLong2;
}
})
.subscribe(this.<String>getPrintSubscriber());
}
在上面的代码中,我们创建了 2 个 Observable,同时调用了 join()
方法,传入的参数中,第一个函数中定义 observableA
发射元素的时间窗口,这里定义为 2 s;第二个函数中定义了 observableB
的时间创建,为 1 s。
我们先根据下面的图理解一下:
observableA
中每隔一秒发射一个元素,时间窗口为 2s,在图上表现为两个大格子;
observableB
每隔两秒发射一个元素,时间窗口为 1s,在图上表现为一个大格子。
我们可以看到,A 先发出 0 ,这时 B 还没有发射元素,所以无法结合。第二秒时 A 发出 2,B 发出 0,这时 A 发出的 0 时间窗口还没关闭,因此 A 的 0 和 2 都和 B 的 0 结合。以此类推,直到一方(这里是 A) 发射完元素后,停止结合。
运行结果:
07-24 18:14:17.735 715-769/top.shixinzhang.rxjavademo I/System.out: A:0
07-24 18:14:18.735 715-769/top.shixinzhang.rxjavademo I/System.out: A:2
07-24 18:14:18.745 715-770/top.shixinzhang.rxjavademo I/System.out: B:0
07-24 18:14:18.745 715-770/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:0/0
07-24 18:14:18.745 715-770/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:2/0
07-24 18:14:19.735 715-769/top.shixinzhang.rxjavademo I/System.out: A:4
07-24 18:14:19.735 715-769/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:4/0
07-24 18:14:20.745 715-769/top.shixinzhang.rxjavademo I/System.out: A:6
07-24 18:14:20.745 715-770/top.shixinzhang.rxjavademo I/System.out: B:3
07-24 18:14:20.745 715-770/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:4/3
07-24 18:14:20.745 715-770/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:6/3
07-24 18:14:21.745 715-769/top.shixinzhang.rxjavademo I/System.out: A:8
07-24 18:14:21.745 715-769/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:8/3
07-24 18:14:22.745 715-770/top.shixinzhang.rxjavademo I/System.out: B:6
07-24 18:14:22.745 715-770/top.shixinzhang.rxjavademo D/SubscriberCreator: onNext: join result:8/6
07-24 18:14:23.745 715-769/top.shixinzhang.rxjavademo D/SubscriberCreator: onCompleted
groupJoin
API 对 groupJoin()
的介绍是:
Returns an Observable that correlates two Observables when they overlap in time and groups the results.
即:将两个 Observable 发射的、时间上重叠的数据关联起来,然后分组结果。
groupJoin()
方法如下:
public final <T2, D1, D2, R> Observable<R> groupJoin(Observable<T2> right, Func1<? super T, ? extends Observable<D1>> leftDuration,
Func1<? super T2, ? extends Observable<D2>> rightDuration,
Func2<? super T, ? super Observable<T2>, ? extends R> resultSelector) {
return unsafeCreate(new OnSubscribeGroupJoin<T, T2, D1, D2, R>(this, right, leftDuration, rightDuration, resultSelector));
}
前三个参数和 join()
一致,不同之处在与第四个参数:
new Func2<Long, Observable<Long>, Observable<String>>() {
@Override
public Observable<String> call(final Long itemA, final Observable<Long> longObservable) {
return longObservable.map(new Func1<Long, String>() {
@Override
public String call(final Long itemB) {
return "groupJoin result:" + itemA + "/" + itemB;
}
});
}
}
它返回的是一个 Observable,而不是一个 Object。
使用例子:
private void groupJoin() {
//产生 0 2 4 6 8
Observable<Long> observableA = Observable.interval(1, TimeUnit.SECONDS)
.map(new Func1<Long, Long>() {
@Override
public Long call(final Long aLong) {
return aLong * 2;
}
})
.take(5);
//产生 0 3 6 9 12
Observable<Long> observableB = Observable.interval(2, TimeUnit.SECONDS)
.map(new Func1<Long, Long>() {
@Override
public Long call(final Long aLong) {
return aLong * 3;
}
})
.take(5);
observableA.groupJoin(observableB,
new Func1<Long, Observable<Long>>() { //定义源 Observable 发射数据的时间窗口
@Override
public Observable<Long> call(final Long aLong) {
System.out.println("A:" + aLong);
return Observable.just(aLong).delay(2000, TimeUnit.MILLISECONDS); //延迟 500 毫秒后发射,即声明周期为 1000毫秒
}
}, new Func1<Long, Observable<Long>>() { //定义第二个 Observable 发射数据的时间窗口
@Override
public Observable<Long> call(final Long aLong) {
System.out.println("B:" + aLong);
return Observable.just(aLong).delay(1000, TimeUnit.MILLISECONDS);
}
}, new Func2<Long, Observable<Long>, Observable<String>>() {
@Override
public Observable<String> call(final Long itemA, final Observable<Long> longObservable) {
return longObservable.map(new Func1<Long, String>() {
@Override
public String call(final Long itemB) {
return "groupJoin result:" + itemA + "/" + itemB;
}
});
}
})
.subscribe(new Action1<Observable<String>>() {
@Override
public void call(final Observable<String> observable) {
observable.subscribe(new Action1<String>() {
@Override
public void call(final String s) {
System.out.println("onNext:" + s);
}
});
}
});
}
运行结果:
07-26 10:46:35.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: A:0
07-26 10:46:36.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: B:0
07-26 10:46:36.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:0/0
07-26 10:46:36.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: A:2
07-26 10:46:36.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:2/0
07-26 10:46:37.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: A:4
07-26 10:46:37.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:4/0
07-26 10:46:38.715 25244-25259/top.shixinzhang.rxjavademo I/System.out: A:6
07-26 10:46:38.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: B:3
07-26 10:46:38.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:4/3
07-26 10:46:38.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:6/3
07-26 10:46:39.725 25244-25259/top.shixinzhang.rxjavademo I/System.out: A:8
07-26 10:46:39.725 25244-25259/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:8/3
07-26 10:46:40.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: B:6
07-26 10:46:40.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:8/6
07-26 10:46:40.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: onNext:groupJoin result:6/6
07-26 10:46:42.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: B:9
07-26 10:46:44.715 25244-25260/top.shixinzhang.rxjavademo I/System.out: B:12
可以看到,groupJoin()
用起来比较费劲啊,目前我还没发现具体的用途。
Merge
Merge
操作符的作用正如它的名字一样,将多个 Observable 发射的数据组合到一个 Observable 中。
Merge
不保证元素发射的顺序,可能会导致顺序错乱(与之对应的是 Concat
操作符,它可以先按顺序发射一个 Observable 发射的数据,然后再按顺序发射下一个的 )。
在上面的图中,一旦有一个 Observable 发出 onError
事件,整个 merge 的过程也就结束了。
为了处理这种问题,在许多 ReactiveX 实现中提供了 MergeDelayError
操作符,它收到 onError
事件后会保留,直到所有 Observable 都发射完数据才传递给观察者。
RxJava 中这两个操作符的实现分别为 :merge
和 mergeDelayError
。
merge
这个图可以比较清晰地表现出 merge
处理 onError
事件的方式。
merge
有 14 种重载,其中主要是接受参数个数的不同,结合前面的操作符可以看到,组合类的操作符很多都这样。
merge
源码:
public static <T> Observable<T> merge(Observable<? extends T> t1, Observable<? extends T> t2) {
return merge(new Observable[] { t1, t2 });
}
public static <T> Observable<T> merge(Observable<? extends T>[] sequences) {
return merge(from(sequences));
}
public static <T> Observable<T> merge(Observable<? extends Observable<? extends T>> source) {
if (source.getClass() == ScalarSynchronousObservable.class) {
return ((ScalarSynchronousObservable<T>)source).scalarFlatMap((Func1)UtilityFunctions.identity());
}
return source.lift(OperatorMerge.<T>instance(false));
}
使用例子:
/**
* 组合两个 Observable 发出的数据,不保证顺序
*/
private void merge() {
Observable<Integer> observableA = Observable.range(0 , 5) //在另外一个线程
.subscribeOn(Schedulers.io());
Observable<Integer> observableB = Observable.range(10, 5);
Observable.merge(observableA, observableB)
.subscribe(this.<Integer>getPrintSubscriber());
}
运行结果:
merge
是静态的类方法,RxJava 还提供了实例方法 mergeWith()
,作用和 merge
一样:
public final Observable<T> mergeWith(Observable<? extends T> t1) {
return merge(this, t1);
}
mergeDelayError
mergeDelayError
和 merge
非常相似,不同之处就在于前面介绍的,对 onError
事件的处理。
Concat
在官方文档中,Concat
属于算数聚合运算符,不输入组合型,但是为了方便介绍相关的操作符,我们在这篇一起了解了吧。
和 Merge
相似但又不同的是,Concat
会按顺序发射多个 Observable 发射的数据,重点就是 按顺序。
Concat
操作符会将多个 Observable 发射的数据组合到一个 Observable 然后发射出去。第一个 Observable 发射的所有数据在第二个 Observable 发射数据之前发射,以此类推。
直到前面一个 Observable 终止,Concat
才会订阅后一个 Observable 。
注意:
如果你想连接一个”热的” Observable(即在创建后立即开始发射数据的 Observable,即使没有订阅者),Concat
将不会看到订阅前“热“ Observable 发射的任何数据。
在一些 ReactiveX 的实现中,还有一个 ConcatMap
操作符 (之前写的 concatMap 的链接),它会将源 Observable 发射的数据进行变换处理,拆分成多个 Observable,然后按顺序链接起来。
StartWith
操作符可以说是位置相反的 Concat
。
RxJava 中对应的实现是 concat
。
RxJava 中 concat()
是一个静态方法,有多种重载,区别就是拼接的 Observable 个数,concat()
会将参数中的 Observable 按在参数中的位置发射出去。
使用起来也很简单,没什么好说的了。
/**
* 按顺序拼接
*/
private void concat() {
Observable<Integer> observableA = Observable.range(0 , 5);
Observable<Integer> observableB = Observable.range(10, 5);
Observable.concat(observableB, observableA)
.subscribe(this.<Integer>getPrintSubscriber());
}
还有一个 concatWith()
方法, Observable.concat(a,b)
等价于 a.concatWith(b)
.
StartWith
StartWith
操作符的作用和名字一样,在源 Observable 发射数据之前插入指定的数据。
如果你想要一个 Observable 在发射数据时先发射一些特定的数据,可以使用 StartWith
;
如果你想要一个 Observable 在发射数据后再发射一些特定的数据,可以使用 Concat
。
RxJava 对应的实现是 startWith()
:
有很多重载,表示可以在前面插入的数据类型可以是 Observable, Iterable 或者直接是几个数据。
startWith()
的实现也是调用的 concat()
:
public final Observable<T> startWith(Observable<T> values) {
return concat(values, this);
}
使用例子:
/**
* 先发射前面的
*/
private void startWith() {
Observable<Integer> observableA = Observable.range(0 , 5);
Observable<Integer> observableB = Observable.range(10, 5);
observableB.startWith(observableA)
.subscribe(this.<Integer>getPrintSubscriber());
}
运行结果:
Switch
Switch
操作符的作用是:将一个发射多个 Observable 的 Observable 变成一个单独的 Observable,它发射那些中间 Observables 最近发射的数据项。
翻译的不太好理解,先上个图:
Switch
订阅一个发射多个 Observable 的 Observable。
每次源 Observable 发射新的 Observable,Switch
会解除对前一个 Observable 的订阅,转向订阅新的 Observable(注意,这个切换的过程发生在源 Observable 发射新的 Observable 时,而不是新 Observable 发射元素时)。
这意味着,在新 Observable 产生到它开始发射数据之前的这段时间里,前一个 Observable 发射的数据将被丢弃(就像上图里的那个黄色圆圈一样)。
RxJava 中对应的实现是 switchOnNext
。
switchOnNext()
是一个静态方法,参数是一个发射 Observable 的 Observable:
public static <T> Observable<T> switchOnNext(Observable<? extends Observable<? extends T>> sequenceOfSequences) {
return sequenceOfSequences.lift(OperatorSwitch.<T>instance(false));
}
使用例子:
/**
* 喜新厌旧,一发射新的 Observable,就取消订阅之前的
*/
private void switchOnNext() {
Observable<Observable<Integer>> observableObservable = Observable.unsafeCreate(new Observable.OnSubscribe<Observable<Integer>>() {
@Override
public void call(final Subscriber<? super Observable<Integer>> subscriber) {
for (int i = 0; i < 5; i++) {
subscriber.onNext(Observable.range(1, 10).delay(i, TimeUnit.SECONDS));
}
subscriber.onCompleted();
}
});
Observable.switchOnNext(observableObservable)
.subscribe(this.<Integer>getPrintSubscriber());
}
运行结果:
还有一个类似的实现是 switchOnNextDelayError
,和 switchOnNext()
的不同之处也是对 onError
事件的处理。
public static <T> Observable<T> switchOnNextDelayError(Observable<? extends Observable<? extends T>> sequenceOfSequences) {
return sequenceOfSequences.lift(OperatorSwitch.<T>instance(true));
}
Thanks
http://reactivex.io/documentation/operators.html
https://github.com/mcxiaoke/RxDocs/blob/master/Operators.md
http://blog.csdn.net/job_hesc/article/details/46612015
http://avenwu.net/2016/05/10/understand-the-join-operation-in-rx/
RxJava 1.x 笔记:组合型操作符的更多相关文章
- RxJava 1.x 笔记:过滤型操作符
我真的是奇怪,上下班的路上看书.看文章学习的劲头特别大,到了周末有大把的学习时间,反而不珍惜,总想打游戏,睡前才踏踏实实地写了篇文章,真是服了自己! 本文内容为 RxJava 官方文档 学习笔记 作者 ...
- 4位组合型Excel文档密码怎么破解
现代社会我们会遇到各种密码,很多的密码我们一段时间不用就不知不觉的忘记了.很多的excel用户就遇到过这种情况,这个时候我们就需要一款Excel密码破解工具.Advanced Office Passw ...
- python3.4学习笔记(十) 常用操作符,条件分支和循环实例
python3.4学习笔记(十) 常用操作符,条件分支和循环实例 #Pyhon常用操作符 c = d = 10 d /= 8 #3.x真正的除法 print(d) #1.25 c //= 8 #用两个 ...
- Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中
一.部署组合型的应用 1.使用配置文件启动replicas集合 k8s通过Replication Controller来创建和管理各个不同的重复容器集合(实际上是重复的pods). Replicati ...
- RxJava系列之二 变换类操作符具体解释1
1.回想 上一篇文章我们主要介绍了RxJava , RxJava 的Observables和 RxJava的just操作符.以及RxJava一些经常使用的操作. 没看过的抓紧点我去看吧. 事实上RxJ ...
- ACAG 0x02-8 非递归实现组合型枚举
ACAG 0x02-8 非递归实现组合型枚举 之所以专门来写这道题的博客,是因为感觉从最根本处了解到了递归的机器实现. 主要的就是两个指令--Call和Ret. Call指令会将返回地址入栈(系统栈) ...
- AcWing 93. 递归实现组合型枚举
AcWing 93. 递归实现组合型枚举 原题链接 从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案. 输入格式 两个整数 n,m ,在同一行用空格隔开. 输出格式 按照从小到大的 ...
- ACWing93.递归实现组合型枚举
题面 \93. 递归实现组合型枚举 从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案. 输入格式 两个整数 n,m ,在同一行用空格隔开. 输出格式 按照从小到大的顺序输出所有方案 ...
- RxJava 1.x 笔记:变换型操作符
在写这几篇 RxJava 笔记时,发现官方文档很久都没有更新啊. 一些前辈两年前写的学习笔记内容跟现在也基本一致,RxJava 2.x 的文档也基本没有,不知道是不是缺实习生. 本文内容为 RxJav ...
随机推荐
- unsigned short A = 10; printf("~A = %u\n", ~A); char c=128; printf("c=%d\n",c); 输出多少?
这是题目给出的答案:第一题,-A =0xfffffff5,int值 为-11,但输出的是uint.所以输出4294967285 第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是 ...
- Ubuntu 12.10 用wubi安装到硬盘中
wubi安装的优势: ubuntu可以像安装软件一样方便的安装.删除,不影响物理机的原有系统 这种方式安装的ubuntu不用担心功能会有所缺失,ubuntu所有的功能都在 和安装了双系统一样,没有什么 ...
- web platform installer
下载链接 https://www.microsoft.com/web/downloads/platform.aspx 默认的安装路径 C:\Program Files\Microsoft\Web Pl ...
- LeetCode——Single Element in a Sorted Array
Question Given a sorted array consisting of only integers where every element appears twice except f ...
- 转载:hdu 题目分类 (侵删)
转载:from http://blog.csdn.net/qq_28236309/article/details/47818349 基础题:1000.1001.1004.1005.1008.1012. ...
- SpringBoot项目结构介绍
一项目结构介绍 springboot框架本身对项目结构并没有特别的要求,但是按照最佳的项目结构可以帮助我们减少可能遇到的错误问题.结构如下: (1)应用主类SpringbootApplication应 ...
- kotlin 记录(已弃坑)
kotlin 有些是转载内容 使用nullable值以及空值检测 引用或函数返回值如果可能为null值,则必须显式标记nullable. (在类型后面跟一个问号表示这个对象可能为空,跟两个感叹号表示这 ...
- 测试php语句执行时间
$start = microtime(true); $elapsed = microtime(true) - $start; echo "That took $elapsed seconds ...
- 机器学习笔记—EM 算法
EM 算法所面对的问题跟之前的不一样,要复杂一些. EM 算法所用的概率模型,既含有观测变量,又含有隐变量.如果概率模型的变量都是观测变量,那么给定数据,可以直接用极大似然估计法,或贝叶斯估计法来估计 ...
- 医疗数据库 Caché 开发笔记
目前所知的 Caché 是应用在医院信息系统(即 HIS),据说在欧美医疗卫生行业,Caché 占了 70% 的市场份额.国内的东华软件就是采用 Caché 数据库,东华软件在国内医院市场占有率大致为 ...