RxJava2.0之旅(六)---过滤操作符

1 类型

    1. 作用
      过滤 / 筛选 被观察者(Observable)发送的事件 & 观察者 (Observer)接收的事件
应用场景 类型 作用 典型实际需求场景
根据指定条件过滤事件 filter() 过滤特定条件的事件 * 功能防抖 * 联想搜索优化
ofType() 过滤特定数据类型的数据
skip() / skiplast() 跳过某个事件
distinct() / distinctUntilChanged() 过滤事件序列中重复的事件/连续重复的事件
根据指定事件数量过滤事件 take() 指定观察者最多能接收到的事件数量
takeLast() 指定观察者只能接收到被观察者发送的最后几个事件
指定时间过滤事件 throttleFirst() / throttleLast() 在某段时间内,只发送该时间段内第一次事件/最后一次事件
Sample() 在某段时间内,只发送该段时间内(最后)1次事件(与throttleLast()操作符类似)
throttleWithTimeout() / debounce() 发送事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次的数据,直到指定时间内都没有新的数据发射时才会发送后一次的数据>
根据指定事件位置过滤事件 firstElement() / lastElement() 仅取第一个元素 / 最后一个元素
elementAt() 指定接收某个元素(通过索引值 确定)(允许越界,即获取的位置索引>发送事件序列长度)
elementAtOrError() 在elementAt()的基础上,当出现越界情况(即获取的位置索引>发送事件序列长度)时,即抛出异常

2 根据 指定条件 过滤事件

2.1 Filter()

  • 作用
    过滤 特定条件的事件
  • 原理


    RxJava2.0之旅(六)---过滤操作符_第1张图片
    944365-cbec5a5b97682ed6.png
  • 具体使用
Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                // 1. 发送5个事件
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
                emitter.onNext(5);
            }

            // 2. 采用filter()变换操作符
        }).filter(new Predicate() {
            // 根据test()的返回值 对被观察者发送的事件进行过滤 & 筛选
              // a. 返回true,则继续发送
              // b. 返回false,则不发送(即过滤)
            @Override
            public boolean test(Integer integer) throws Exception {
                return integer > 3;
                // 本例子 = 过滤了整数≤3的事件
            }
        }).subscribe(new Observer() {

            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "开始采用subscribe连接");
            }

            @Override
            public void onNext(Integer value) {
                Log.d(TAG, "过滤后得到的事件是:"+ value  );
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "对Error事件作出响应");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "对Complete事件作出响应");
            }
        });
  • 测试结果


    QQ截图20180715010429.png

2.2 ofType()

  • 作用
    过滤 特定数据类型的数据
  • 具体使用
Observable.just(1, "Carson", 3, "Ho", 5)
                  .ofType(Integer.class) // 筛选出 整型数据
                  .subscribe(new Consumer() {
                      @Override
                      public void accept( Integer integer) throws Exception {
                          Log.d(TAG,"获取到的整型事件元素是: "+ integer);
                      }
        });
  • 测试结果


    QQ截图20180715010716.png

2.3 skip() /skipLast()

  • 作用
    跳过某个事件
  • 具体使用
// 使用1:根据顺序跳过数据项
        Observable.just(1, 2, 3, 4, 5)
                .skip(1) // 跳过正序的前1项
                .skipLast(2) // 跳过正序的后2项
                  .subscribe(new Consumer() {
                      @Override
                      public void accept( Integer integer) throws Exception {
                          Log.d(TAG,"获取到的整型事件元素是: "+ integer);
                      }
        });

// 使用2:根据时间跳过数据项
        // 发送事件特点:发送数据0-5,每隔1s发送一次,每次递增1;第1次发送延迟0s
        Observable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS)
                .skip(1, TimeUnit.SECONDS) // 跳过第1s发送的数据
                .skipLast(1, TimeUnit.SECONDS) // 跳过最后1s发送的数据
                .subscribe(new Consumer() {

                    @Override
                    public void accept( Long along ) throws Exception {
                        Log.d(TAG,"获取到的整型事件元素是: "+ along);
                    }
                });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第2张图片
    QQ截图20180715011215.png

2.4 distinct() / distinctUntilChanged()

  • 作用
    过滤事件序列中重复的事件 / 连续重复的事件
  • 具体使用
// 使用1:过滤事件序列中重复的事件
        Observable.just(1, 2, 3, 1 , 2 )
                .distinct()
                .subscribe(new Consumer() {
                      @Override
                      public void accept( Integer integer) throws Exception {
                          Log.d(TAG,"不重复的整型事件元素是: "+ integer);
                      }
        });

        // 使用2:过滤事件序列中 连续重复的事件
        // 下面序列中,连续重复的事件 = 3、4
        Observable.just(1,2,3,1,2,3,3,4,4 )
                .distinctUntilChanged()
                .subscribe(new Consumer() {
                    @Override
                    public void accept( Integer integer) throws Exception {
                        Log.d(TAG,"不连续重复的整型事件元素是: "+ integer);
                    }
                });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第3张图片
    QQ截图20180715011644.png

3 根据 指定事件数量 过滤事件

  • 需求场景
    通过设置指定的事件数量,仅发送特定数量的事件
  • 对应操作符类型
    take() &takeLast()

3.1 take()

  • 作用
    指定观察者最多能接收到的事件数量

  • 原理


    RxJava2.0之旅(六)---过滤操作符_第4张图片
    944365-0ce65f078ec3d259.png
  • 具体使用

Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                // 1. 发送5个事件
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
                emitter.onNext(5);
            }

            // 采用take()变换操作符
            // 指定了观察者只能接收2个事件
        }).take(2)
        .subscribe(new Observer() {

            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "开始采用subscribe连接");
            }

            @Override
            public void onNext(Integer value) {
                Log.d(TAG, "过滤后得到的事件是:"+ value  );
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "对Error事件作出响应");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "对Complete事件作出响应");
            }
        });

// 实际上,可理解为:被观察者还是发送了5个事件,只是因为操作符的存在拦截了3个事件,最终观察者接收到的是2个事件
  • 测试结果


    QQ截图20180715012204.png

3.2 takeLast()

  • 作用
    指定观察者只能接收到被观察者发送的最后几个事件
  • 具体使用
Observable.just(1, 2, 3, 4, 5)
          .takeLast(3) //指定观察者只能接受被观察者发送的3个事件
          .subscribe(new Observer() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "开始采用subscribe连接");
            }

            @Override
            public void onNext(Integer value) {
                Log.d(TAG, "过滤后得到的事件是:"+ value  );
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "对Error事件作出响应");
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "对Complete事件作出响应");
            }
        });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第5张图片
    QQ截图20180715012358.png

4 根据 指定时间 过滤事件

  • 需求场景
    通过设置指定的时间,仅发送在该时间内的事件

4.1 throttleFirst()/ throttleLast()

  • 作用
    在某段时间内,只发送该段时间内第1次事件 / 最后1次事件

如,1段时间内连续点击按钮,但只执行第1次的点击操作

  • 原理示意图


    RxJava2.0之旅(六)---过滤操作符_第6张图片
    944365-1f42132c7350bd79.png
  • 具体使用
<<- 在某段时间内,只发送该段时间内第1次事件 ->>
Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter e) throws Exception {
                // 隔段事件发送时间
                e.onNext(1);
                Thread.sleep(500);
                
                e.onNext(2);
                Thread.sleep(400);
                
                e.onNext(3);
                Thread.sleep(300);
                
                e.onNext(4);
                Thread.sleep(300);
                
                e.onNext(5);
                Thread.sleep(300);
                
                e.onNext(6);
                Thread.sleep(400);
                
                e.onNext(7);
                Thread.sleep(300);
                e.onNext(8);

                Thread.sleep(300);
                e.onNext(9);

                Thread.sleep(300);
                e.onComplete();
            }
        }).throttleFirst(1, TimeUnit.SECONDS)//每1秒中采用数据
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d(TAG, "开始采用subscribe连接");
                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.d(TAG, "接收到了事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });


<<- 在某段时间内,只发送该段时间内最后1次事件 ->>
Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter e) throws Exception {
                // 隔段事件发送时间
                e.onNext(1);
                Thread.sleep(500);

                e.onNext(2);
                Thread.sleep(400);

                e.onNext(3);
                Thread.sleep(300);

                e.onNext(4);
                Thread.sleep(300);

                e.onNext(5);
                Thread.sleep(300);

                e.onNext(6);
                Thread.sleep(400);

                e.onNext(7);
                Thread.sleep(300);
                e.onNext(8);

                Thread.sleep(300);
                e.onNext(9);

                Thread.sleep(300);
                e.onComplete();
            }
        }).throttleLast(1, TimeUnit.SECONDS)//每1秒中采用数据
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d(TAG, "开始采用subscribe连接");
                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.d(TAG, "接收到了事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });
  • 测试结果


    QQ截图20180715013038.png

    RxJava2.0之旅(六)---过滤操作符_第7张图片
    QQ截图20180715013053.png

4.2 Sample()

  • 作用
    在某段时间内,只发送该段时间内最新(最后)1次事件

throttleLast() 操作符类似

  • 具体使用
    仅需要把上文的 throttleLast() 改成Sample()操作符即可,此处不作过多描述

4.3 throttleWithTimeout () / debounce()

  • 作用
    发送数据事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次的数据,直到指定时间内都没有新数据发射时才会发送后一次的数据
  • 具体使用
Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter e) throws Exception {
                // 隔段事件发送时间
                e.onNext(1);
                Thread.sleep(500);
                e.onNext(2); // 1和2之间的间隔小于指定时间1s,所以前1次数据(1)会被抛弃,2会被保留
                Thread.sleep(1500);  // 因为2和3之间的间隔大于指定时间1s,所以之前被保留的2事件将发出
                e.onNext(3);
                Thread.sleep(1500);  // 因为3和4之间的间隔大于指定时间1s,所以3事件将发出
                e.onNext(4);
                Thread.sleep(500); // 因为4和5之间的间隔小于指定时间1s,所以前1次数据(4)会被抛弃,5会被保留
                e.onNext(5);
                Thread.sleep(500); // 因为5和6之间的间隔小于指定时间1s,所以前1次数据(5)会被抛弃,6会被保留
                e.onNext(6);
                Thread.sleep(1500); // 因为6和Complete实践之间的间隔大于指定时间1s,所以之前被保留的6事件将发出

                e.onComplete();
            }
        }).throttleWithTimeout(1, TimeUnit.SECONDS)//每1秒中采用数据
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.d(TAG, "接收到了事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第8张图片
    QQ截图20180715013703.png

5 根据 指定事件位置 过滤事件

  • 需求场景
    通过设置指定的位置,过滤在该位置的事件

5.1 firstElement() / lastElement()

  • 作用
    仅选取第1个元素 / 最后一个元素
  • 具体使用
// 获取第1个元素
        Observable.just(1, 2, 3, 4, 5)
                  .firstElement()
                  .subscribe(new Consumer() {
                      @Override
                      public void accept( Integer integer) throws Exception {
                          Log.d(TAG,"获取到的第一个事件是: "+ integer);
                      }
        });

// 获取最后1个元素
        Observable.just(1, 2, 3, 4, 5)
                .lastElement()
                .subscribe(new Consumer() {
                    @Override
                    public void accept( Integer integer) throws Exception {
                        Log.d(TAG,"获取到的最后1个事件是: "+ integer);
                    }
                });
  • 测试结果


    QQ截图20180715014022.png

5.2 elementAt()

  • 作用
    指定接收某个元素(通过 索引值 确定)

注:允许越界,即获取的位置索引 > 发送事件序列长度

  • 具体使用
// 使用1:获取位置索引 = 2的 元素
        // 位置索引从0开始
        Observable.just(1, 2, 3, 4, 5)
                  .elementAt(2)
                  .subscribe(new Consumer() {
                      @Override
                      public void accept( Integer integer) throws Exception {
                          Log.d(TAG,"获取到的事件元素是: "+ integer);
                      }
        });

// 使用2:获取的位置索引 > 发送事件序列长度时,设置默认参数
        Observable.just(1, 2, 3, 4, 5)
                .elementAt(6,10)
                .subscribe(new Consumer() {
                    @Override
                    public void accept( Integer integer) throws Exception {
                        Log.d(TAG,"获取到的事件元素是: "+ integer);
                    }
                });
  • 测试结果


    QQ截图20180715014219.png

5.3

  • 作用
    elementAt()的基础上,当出现越界情况(即获取的位置索引 > 发送事件序列长度)时,即抛出异常
  • 具体使用
Observable.just(1, 2, 3, 4, 5)
                .elementAtOrError(6)
                .subscribe(new Consumer() {
                    @Override
                    public void accept( Integer integer) throws Exception {
                        Log.d(TAG,"获取到的事件元素是: "+ integer);
                    }
                });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第9张图片
    944365-0d8ba7c83413d000.png

6 实际应用

6.1 功能防抖

RxJava2.0之旅(六)---过滤操作符_第10张图片
QQ截图20180715180015.png
// 注册控件
        Button button;
        button = (Button)findViewById(R.id.button);

        /*
         * 1. 此处采用了RxBinding:RxView.clicks(button) = 对控件点击进行监听,需要引入依赖:compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
         * 2. 传入Button控件,点击时,都会发送数据事件(但由于使用了throttleFirst()操作符,所以只会发送该段时间内的第1次点击事件)
         **/
        RxView.clicks(button)
                .throttleFirst(2, TimeUnit.SECONDS)  // 才发送 2s内第1次点击按钮的事件
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(Object value) {
                        Log.d(TAG, "发送了网络请求" );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应" + e.toString());
                        // 获取异常错误信息
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });
 
 
  • 测试结果
    在2s内,无论点击多少次,也只会发送1次网络请求


    RxJava2.0之旅(六)---过滤操作符_第11张图片
    944365-851ce8b8bc51bd0b.gif

6.2 联想搜索优化

RxJava2.0之旅(六)---过滤操作符_第12张图片
QQ截图20180715180602.png

RxJava2.0之旅(六)---过滤操作符_第13张图片
QQ截图20180715180626.png
// 控件绑定
        EditText ed;
        TextView tv;
        ed = (EditText) findViewById(R.id.ed);
        tv = (TextView) findViewById(R.id.tv);
        
         /*
         * 说明
         * 1. 此处采用了RxBinding:RxTextView.textChanges(name) = 对对控件数据变更进行监听(功能类似TextWatcher),需要引入依赖:compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
         * 2. 传入EditText控件,输入字符时都会发送数据事件(此处不会马上发送,因为使用了debounce())
         * 3. 采用skip(1)原因:跳过 第1次请求 = 初始输入框的空字符状态
         **/
        RxTextView.textChanges(ed)
                .debounce(1, TimeUnit.SECONDS).skip(1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(CharSequence charSequence) {
                        tv.setText("发送给服务器的字符 = " + charSequence.toString());
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "对Error事件作出响应" );

                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "对Complete事件作出响应");
                    }
                });
  • 测试结果


    RxJava2.0之旅(六)---过滤操作符_第14张图片
    944365-e691a4550597d7c7.gif

参考

Android RxJava:过滤操作符 全面讲解

你可能感兴趣的:(RxJava2.0之旅(六)---过滤操作符)