rxjava2变换运算符

rxjava一样提供了很多变换运算符帮助我们更简单的转转发出的Observable。这些变换运算符也是我们相对来说比较常用到的,所以对于每个变换运算符我们都单独拿出来简单记录下。

Buffer

定期将Observable发出的项目收集到束中并发出这些束,而不是一次发送一个项目。Buffer运算符将一个Observable转换为另一个Observable,该Observable将发出这些项的缓冲集合。
上面这句话可能难以直接理解,其实buffer顾名思义就是缓冲,rxjava提供buffer可以让我们按大小和时间来缓冲发出的数据,等缓冲条件满足或者发射结束后再发出缓冲的数据。

buffer提供了如下几种方法,我们来简单说下

android top 里面buffers是什么_缓存

1.buffer(int count)

以列表的形式发出非重叠缓冲区,每个缓冲区为一组发出。

android top 里面buffers是什么_List_02


举个例子,如果发射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发出的项不在任何缓冲区中)。

android top 里面buffers是什么_ide_03


这个方法主要注意的参数是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)

按时间片段缓存,等时发送缓存区的一组数据。

android top 里面buffers是什么_ide_04


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。

android top 里面buffers是什么_List_05

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并将其作为自己的发射发出。

android top 里面buffers是什么_ide_06


这个方法看起来有点麻烦,其实简单来说就是监听了两个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的部分就只写这么多,其他的方法其实万变不离其中,只是不同的方法控制缓存区开启结束的条件不同而已。