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

来源:互联网 发布:淘宝卖家怎样包运费险 编辑:程序博客网 时间:2024/06/05 07:12

一、过滤操作符列表

用于过滤和选择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: 402-10 10:24:05.928 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 502-10 10:24:06.438 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 602-10 10:24:07.039 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 702-10 10:24:07.739 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 802-10 10:24:08.540 31354-8852/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 902-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: 602-10 10:26:40.869 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 702-10 10:26:41.569 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 802-10 10:26:42.370 10474-11359/cn.com.minstone.rxjavalearn E/SearchActivity: accept: 902-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: 收到数据102-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据202-20 09:05:51.688 28437-28437/? E/FilterActivity: 收到数据302-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: 点击了按钮");            }        });
2 0
原创粉丝点击