[Android开发] RxJava2之路五 - 过滤操作符例子Demo

一、过滤操作符列表

用于过滤和选择Observable发射的数据序列

方法含义
filter()过滤数据
takeLast()只发射最后的N项数据
last()只发射最后的一项数据
lastOrDefault()只发射最后的一项数据,如果Observable为空就发射默认值
takeLastBuffer()将最后的N项数据当做单个数据发射
skip()跳过开始的N项数据
skipLast()跳过最后的N项数据
take()只发射开始的N项数据
first() , takeFirst()只发射第一项数据,或者满足某种条件的第一项数据
firstOrDefault()只发射第一项数据,如果Observable为空就发射默认值
elementAt()发射第N项数据
elementAtOrDefault()发射第N项数据,如果Observable数据少于N项就发射默认值
sample() , throttleLast()定期发射Observable最近的数据
throttleFirst()定期发射Observable发射的第一项数据
throttleWithTimeout() , debounce()只有在空闲了一段时间后才发射数据,通俗的说,就是如果一段时间没有操作,就执行一次操作
timeout()如果在一个指定的时间段后还没发射数据,就发射一个异常
distinct()过滤掉重复数据
distinctUntilChanged()过滤掉连续重复的数据
ofType()只发射指定类型的数据
ignoreElements()丢弃所有的正常数据,只发射错误或完成通知

二、过滤操作符

2.1 debounce

被观察者连续发射的数据的时间间隔 如果在指定时间 就被过滤拦截。

看一个栗子:

    public void test(){
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                if(e.isDisposed()) return;
                try {
                    //产生结果的间隔时间分别为100、200、300...1000毫秒
                    for (int i = 1; i <= 10; i++) {
                        e.onNext(i);   //发射数据
                        Thread.sleep(i * 100);
                    }
                    e.onComplete();
                }catch(Exception ex){
                    e.onError(ex);
                }
            }
        }).subscribeOn(Schedulers.computation()) //被观察者在线程中执行
                .debounce(400,TimeUnit.MILLISECONDS)  //如果发射数据间隔少于400就过滤拦截掉
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG, "accept: "+integer);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e(TAG, "出错: "+throwable.toString());

                    }
                });
    }

输出是这样的,400毫秒以前的就被过滤掉了:

02-10 10:24:05.527 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 4
02-10 10:24:05.928 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 5
02-10 10:24:06.438 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 6
02-10 10:24:07.039 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 7
02-10 10:24:07.739 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 8
02-10 10:24:08.540 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 9
02-10 10:24:09.441 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 10

2.2 filter

过滤数据,返回真就是满足条件,不拦截; 返回假就是不满足条件,拦截掉,不然观察者接收到。

这个可以对上面的编辑框输入搜索进一步优化,当内容为空的时候就过滤掉。

看一个栗子(上面的修改一下):

    public void test(){
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                if(e.isDisposed()) return;
                try {
                    //产生结果的间隔时间分别为100、200、300...1000毫秒
                    for (int i = 1; i <= 10; i++) {
                        e.onNext(i);
                        Thread.sleep(i * 100);
                    }
                    e.onComplete();
                }catch(Exception ex){
                    e.onError(ex);
                }
            }
        }).subscribeOn(Schedulers.computation())
                .debounce(400,TimeUnit.MILLISECONDS)  //如果发射数据间隔少于400就过滤拦截掉
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Exception {
                        //返回真就是满足条件,不拦截; 返回假就是不满足条件,拦截掉,不然观察者接收到。

                        //大于5的才满足条件,才不拦截
                        return integer > 5;
                    }
                })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG, "accept: "+integer);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e(TAG, "出错: "+throwable.toString());

                    }
                });
    }

对应输出的结果就是输出6以及6之后的数据:

02-10 10:26:40.268 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 6
02-10 10:26:40.869 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 7
02-10 10:26:41.569 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 8
02-10 10:26:42.370 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 9
02-10 10:26:43.271 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 10

2.3 take操作符

    public void testLast(){
        Observable.just(1, 2, 3, 4, 5, 6, 7, 8)
                .take(4)   //发射前面四个数据
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e(TAG,"收到数据"+value);
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

调用上面的方法,输出的是:

02-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据1
02-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据2
02-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据3
02-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据4

其他的过滤操作符就自行测试了。

三、过滤的实际例子

3.1 搜索例子

比如在做搜索的时候,可以使用debounce减少频繁的网络请求。避免每输入(删除)一个字就做一次网络请求。

不使用Rxbinding的栗子:

        etTest = (EditText) findViewById(R.id.et_test);

        etTest.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(final Editable s) {
                //交给RxJava去做
                if(disposable != null && !disposable.isDisposed()){
                    disposable.dispose();
                }

                disposable = Observable.create(new ObservableOnSubscribe<String>() {
                            @Override
                            public void subscribe(ObservableEmitter<String> e) throws Exception {
                                e.onNext(s.toString());
                            }
                        })
                        .debounce(400, TimeUnit.MILLISECONDS)
                        .subscribeOn(AndroidSchedulers.mainThread())
                        .filter(new Predicate<String>() {
                            @Override
                            public boolean test(String s) throws Exception {
                                 //返回是否满足条件,真为继续执行下去,假不满足条件就是拦截了
                                return s.trim().length() > 0;
                            }
                        })
                        .flatMap(new Function<String, ObservableSource<List<String>>>() {
                            @Override
                            public ObservableSource<List<String>> apply(String string) throws Exception {
                                List<String> list = new ArrayList<String>();
                                for(Character charText:string.toCharArray()){
                                    list.add(charText.toString());
                                }
                                return Observable.just(list);
                            }
                        })
                        .observeOn(Schedulers.io())
                        .subscribe(new Consumer<List<String>>() {
                            @Override
                            public void accept(List<String> strings) throws Exception {
                                Log.e(TAG, "accept: "+strings.size());
                            }
                        });
            }
        });



    }

这样子当你不停在输入EditText的内容的时候,是不会打印的啦

使用了Rxbinding的栗子:

这里配合Rxbinding,利用这篇文章打包的rxbinding2all:http://blog.csdn.net/niubitianping/article/details/56014611

    public void testDemo() {
        RxTextView.textChangeEvents(etTest)
                .debounce(300, TimeUnit.MILLISECONDS) //300毫秒内的连续编辑  过滤掉
                .flatMap(new Function<TextViewTextChangeEvent, ObservableSource<String>>() {
                    @Override
                    public ObservableSource<String> apply(@NonNull TextViewTextChangeEvent textViewTextChangeEvent) throws Exception {
                        //把发射的数据源变为文本String
                        return Observable.just(textViewTextChangeEvent.text().toString());
                    }
                })
                .filter(new Predicate<String>() {
                    @Override
                    public boolean test(@NonNull String s) throws Exception {
                        //是否同意继续发射
                        return s.length()>0;
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        Log.e(TAG, "accept: "+s);
                    }
                });
    }

3.2 防止多次点击

点击一个按钮,取1秒内的第一次点击响应,防止多次点击。

Rxbinding例子:

这例子使用debounce也可以实现,但是实现的过成不一样,如果用的是debounce,必须得等待指定的事时间。如果用的是throttleFirst就是不用等待,执行第一个,指定时间的事件都过滤掉。这点要注意。

btTest = (Button) findViewById(R.id.bt_test);

RxView.clicks(btTest)
        .throttleFirst(1, TimeUnit.SECONDS)   //一秒内的点击只拿第一个,他的全过滤掉
        .subscribe(new Action1<Void>() {

            @Override
            public void call(Void aVoid) {
                //onNext回调
                Log.e(TAG, "call: 点击了按钮");
            }
        });
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepStudya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值