一、过滤操作符列表
用于过滤和选择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: 点击了按钮");
}
});