rxjava2变换运算符
rxjava一样提供了很多变换运算符帮助我们更简单的转转发出的Observable。这些变换运算符也是我们相对来说比较常用到的,所以对于每个变换运算符我们都单独拿出来简单记录下。
Buffer
定期将Observable发出的项目收集到束中并发出这些束,而不是一次发送一个项目。Buffer运算符将一个Observable转换为另一个Observable,该Observable将发出这些项的缓冲集合。
上面这句话可能难以直接理解,其实buffer顾名思义就是缓冲,rxjava提供buffer可以让我们按大小和时间来缓冲发出的数据,等缓冲条件满足或者发射结束后再发出缓冲的数据。
buffer提供了如下几种方法,我们来简单说下
1.buffer(int count)
以列表的形式发出非重叠缓冲区,每个缓冲区为一组发出。
举个例子,如果发射0到9共十个数,设置缓冲区size为3,则会每缓冲3个元素就绪后就将这几个为一组直接发出,直到最后将剩余的数据为一组发出。
private void doSomeWork() {
Observable.just("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
.buffer(3)
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(List<String> stringList) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (String value : stringList) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果
accept : value : [0,1,2,]
accept : value : [3,4,5,]
accept : value : [6,7,8,]
accept : value : [9,]
2.buffer(count, skip)
从第一项开始,取count个项创建缓存,从第一项开始skip个项之后再取count个项创建缓存。根据count和skip的值,这些缓冲区可能重叠(多个缓冲区可能包含相同的项),也可能有间隙(源Observable发出的项不在任何缓冲区中)。
这个方法主要注意的参数是skip,skip故名思义是跳过,由于第一次缓存后是每跳过skip个元素后再去取元素缓存,所以有三种情况发生
1.count = skip 非重叠不遗漏缓冲,等同于buffer(int count)
2.count > skip 重叠不遗漏缓冲
3.count < skip 非重叠遗漏缓冲
为方便理解,我一样写下例子。先举个count > skip的。
如果发射0到9共十个数,设置缓冲区size为3,skip为2,则每次缓冲3个元素为一组发出,第一次发出0,1,2,这时skip两个元素,0和1,下一次缓存则从元素2开始,缓存3个元素,即2,3,4,依次类似。
private void doSomeWork() {
Observable.just("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
.buffer(3, 2)
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(List<String> stringList) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (String value : stringList) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果,可发现count > skip时,缓冲区元素被重叠了一部分
accept : value : [0,1,2,]
accept : value : [2,3,4,]
accept : value : [4,5,6,]
accept : value : [6,7,8,]
accept : value : [8,9,]
再举个count < skip的例子。如果发射0到9共十个数,设置缓冲区size为2,skip为3,则每次缓冲2个元素为一组发出,第一次发出0,1,这时skip三个元素,0、1和2,下一次缓存则从元素3开始,缓存2个元素,即3,4,依次类似。
private void doSomeWork() {
Observable.just("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
.buffer(2, 3)
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(List<String> stringList) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (String value : stringList) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果,可发现count < skip时,缓冲区元素没有重叠,但有一部分元素被遗漏
accept : value : [0,1,]
accept : value : [3,4,]
accept : value : [6,7,]
accept : value : [9,]
3.buffer(long timespan, TimeUnit unit)
按时间片段缓存,等时发送缓存区的一组数据。
buffer不仅可以按元素个数来分组,也可以按时间片段来分组,与上面按元素个数分组类似,只是将分组的条件换成了时间值。
一样举个例子,我们每隔100ms发送一个元素,每隔250ms缓冲一组,看看打印结果
private void doSomeWork() {
Observable.interval(100, TimeUnit.MILLISECONDS)
.take(10)
.buffer(250, TimeUnit.MILLISECONDS)
.subscribe(new Consumer<List<Long>>() {
@Override
public void accept(List<Long> longs) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (Long value : longs) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果
accept : value : [0,1,]
accept : value : [2,3,]
accept : value : [4,5,6,]
accept : value : [7,8,9,]
按时间缓存,元素的个数取决于这段时间里面总共发出的个数,所以缓存集合的size是不固定的,可能为空,也可能很多。
4.buffer(boundary[, initialCapacity])
buffer(boundary)监视一个Observable边界。 每次Observable发出一个项目时,它都会创建一个新的List来开始收集源Observable发出的项目并发出前一个List。
buffer(boundary[, initialCapacity])这个方法分组缓存的条件是以另外一个Observable边界为条件,也就是说当另外一个Observable开始发射信号时,会触发缓存的条件。我们把上面按时间分组的例子更改下,用边界分组的方式实现。
private void doSomeWork() {
Observable.interval(100, TimeUnit.MILLISECONDS)
.take(10)
.buffer(Observable.interval(250,TimeUnit.MILLISECONDS))
.subscribe(new Consumer<List<Long>>() {
@Override
public void accept(List<Long> longs) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (Long value : longs) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果。监听到Observable.interval(250,TimeUnit.MILLISECONDS)的信号时产生分组。
accept : value : [0,1,]
accept : value : [2,3,4,]
accept : value : [5,6,]
accept : value : [7,8,]
accept : value : [9,]
5.buffer(bufferOpenings, bufferClosingSelector)
bufferOpenings,它发出BufferOpening对象。 每次观察到这样一个发射的项目时,bufferOpenings会创建一个新的List来开始收集source Observable发出的项目,并将bufferOpenings Observable传递给closingSelector函数。 closingSelector函数也返回一个Observable。 缓冲区监视closingSelector函数返回的Observable,当检测到它的发射项时,它会关闭List并将其作为自己的发射发出。
这个方法看起来有点麻烦,其实简单来说就是监听了两个Observable发射时间作为缓冲区开始和结束的节点。
我们一样来举个例子,
private void doSomeWork() {
Observable.interval(100, TimeUnit.MILLISECONDS)
.take(10)
.buffer(Observable.interval(250, TimeUnit.MILLISECONDS).flatMap(new Function<Long, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Long aLong) throws Exception {
String str = "this aLong is " + aLong;
Log.d(TAG, "openingIndicator apply :" + str);
return Observable.just(str);
}
}), new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(String s) throws Exception {
return Observable.interval(200, TimeUnit.MILLISECONDS).flatMap(new Function<Long, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Long aLong) throws Exception {
String str = "this aLong is " + aLong;
Log.d(TAG, "closingIndicator apply :" + str);
return Observable.just(str);
}
});
}
})
.subscribe(new Consumer<List<Long>>() {
@Override
public void accept(List<Long> longs) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (Long value : longs) {
builder.append(value + ",");
}
builder.append("]");
Log.d(TAG, " accept : value : " + builder.toString());
}
});
}
打印结果,由于interval第一个缓冲区开始是在250ms的时刻,前面source Observable每隔100ms发射一个数据,已经发射出去了0和1,所以打印accept第一组是[2,3]。
openingIndicator apply :this aLong is 0
closingIndicator apply :this aLong is 0
accept : value : [2,3,]
openingIndicator apply :this aLong is 1
closingIndicator apply :this aLong is 0
accept : value : [5,6,]
openingIndicator apply :this aLong is 2
closingIndicator apply :this aLong is 0
accept : value : [7,8,]
openingIndicator apply :this aLong is 3
accept : value : [9,]
上面的例子我们没有使用bufferOpenings和bufferClosingSelector里的Observable发射的数据,他们对source Observable发射的数据来说没有关系,只是当bufferOpenings和bufferClosingSelector发射数据时,控制buffer开始和结束的缓冲时间节点。
好了,buffer的部分就只写这么多,其他的方法其实万变不离其中,只是不同的方法控制缓存区开启结束的条件不同而已。