前言
上一篇文章我們學(xué)習(xí)了轉(zhuǎn)換類操作符钥勋,本篇我們將一起來學(xué)習(xí)RxJava過濾類操作符炬转。過濾操作符主要是用來對事件數(shù)據(jù)進(jìn)行過濾與篩選控汉,只返回滿足條件的數(shù)據(jù),一起來看下都有哪些返吻。
過濾操作符
Filter
filter操作符姑子,按照一定的約束條件過濾序列中我們不想要的數(shù)據(jù),只返回滿足條件的數(shù)據(jù)給觀察者测僵。
//結(jié)合flatmap街佑,過濾出各小區(qū)中房源大小大于120平的房子
Observable.from(communities)
.flatMap(new Func1<Community, Observable<House>>() {
@Override
public Observable<House> call(Community community) {
return Observable.from(community.getHouses());
}
})
.filter(new Func1<House, Boolean>() {
@Override
public Boolean call(House house) {
return house.getSize() > 120f;
}
})
.subscribe(new Action1<House>() {
@Override
public void call(House house) {
Log.e("rx_test", "filter:大于120平的房子:" + house.getCommunityName() + "小區(qū),大泻纯俊:" + house.getSize());
}
});
由代碼可見沐旨,我們需要new一個(gè)Func1對象給filter(),Func1<House, Boolean>()
中第一個(gè)是由觀測序列傳入數(shù)據(jù)的類型榨婆,第二個(gè)是返回是否過濾的Boolean對象磁携。滿足filter()的條件則返回true,否則返回false良风。并將返回為true的數(shù)據(jù)發(fā)射給觀察者谊迄。
輸出結(jié)果:
filter:大于120平的房子:東方花園小區(qū),大醒萄搿:144.8
filter:大于120平的房子:東方花園小區(qū)统诺,大小:144.8
filter:大于120平的房子:馬德里春天小區(qū)疑俭,大辛改亍:123.4
filter:大于120平的房子:馬德里春天小區(qū),大谐А:123.4
filter:大于120平的房子:帝豪家園小區(qū)啄寡,大小:188.7
filter:大于120平的房子:帝豪家園小區(qū)哩照,大型ξ铩:188.7
filter:大于120平的房子:帝豪家園小區(qū),大衅厦搿:188.7
原理圖:
實(shí)際項(xiàng)目開發(fā)中姻乓,filter操作符可用來過濾數(shù)據(jù)集合中的null值,方便實(shí)用眯牧。
Take
take(int count)操作符蹋岩,可用來截取觀測序列中前count個(gè)元素并發(fā)射。
//take:獲取前兩個(gè)小區(qū)名
Observable.from(communities)
.take(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "take:前兩個(gè)小區(qū):" + community.getCommunityName());
}
});
輸出結(jié)果:
take:前兩個(gè)小區(qū):東方花園
take:前兩個(gè)小區(qū):馬德里春天
原理圖:
TakeLast
takeLast(int count)操作符学少,顧名思義剪个,截取觀測序列中后count個(gè)元素并發(fā)射。
//takeLast:獲取后兩個(gè)小區(qū)名
Observable.from(communities)
.takeLast(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "takeLast:后兩個(gè)小區(qū):" + community.getCommunityName());
}
});
輸出結(jié)果:
takeLast:后兩個(gè)小區(qū):馬德里春天
takeLast:后兩個(gè)小區(qū):帝豪家園
原理圖:
takeUntil操作符有兩種類型的入?yún)ⅰ?p>
1.takeUntil(Observable)
訂閱并開始發(fā)射原始Observable版确,同時(shí)監(jiān)視我們提供的第二個(gè)Observable扣囊。如果第二個(gè)Observable發(fā)射了一項(xiàng)數(shù)據(jù)或者發(fā)射了一個(gè)終止通知乎折,takeUntil()返回的Observable會(huì)停止發(fā)射原始Observable并終止。
//observableA每300ms發(fā)射一個(gè)Long型自增數(shù)據(jù)
//observableB每800ms發(fā)射一個(gè)Long型自增數(shù)據(jù)
Observable<Long> observableA = Observable.interval(300, TimeUnit.MILLISECONDS);
Observable<Long> observableB = Observable.interval(800, TimeUnit.MILLISECONDS);
observableA.takeUntil(observableB)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
Log.e("rx_test", "takeUntil(Observable):" + "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.e("rx_test", "takeUntil(Observable):onError:" + e.getMessage());
}
@Override
public void onNext(Long aLong) {
Log.e("rx_test", "takeUntil(Observable):onNext:" + aLong);
}
});
輸出結(jié)果:
takeUntil(Observable):onNext:0
takeUntil(Observable):onNext:1
takeUntil(Observable):onCompleted
由輸出結(jié)果可看出侵歇,訂閱之后骂澄,observableA依次發(fā)射0,1之后就發(fā)射onCompleted標(biāo)記停止了惕虑。這是由于observableA每300ms發(fā)射一次坟冲,當(dāng)發(fā)射完1后,時(shí)間已過去600ms溃蔫,到800ms時(shí)observableB開始發(fā)射數(shù)據(jù)健提,takeUntil起作用則中斷了observableA的發(fā)射。
原理圖:
2.takeUntil(Func1)
通過傳入的Func1中的call()方法判斷是否中止發(fā)射數(shù)據(jù)伟叛。
//takeUntil:與flatmap結(jié)合過濾直到房價(jià)大于500時(shí)中斷當(dāng)前小Observable發(fā)射House
Observable.from(communities)
.flatMap(new Func1<Community, Observable<House>>() {
@Override
public Observable<House> call(Community community) {
return Observable.from(community.getHouses());
}
})
.takeUntil(new Func1<House, Boolean>() {
@Override
public Boolean call(House house) {
return house.getPrice() > 500;
}
})
.subscribe(new Action1<House>() {
@Override
public void call(House house) {
Log.e("rx_test", "takeUntil:大于500時(shí)中斷發(fā)射:" + house.getCommunityName() + "小區(qū)私痹,房價(jià):" + house.getPrice());
}
});
輸出結(jié)果:
takeUntil(Func1):大于500時(shí)中斷發(fā)射:東方花園小區(qū),房價(jià):200
takeUntil(Func1):大于500時(shí)中斷發(fā)射:東方花園小區(qū)统刮,房價(jià):520
原理圖:
TakeWhile
takeWhile操作符紊遵,類似于takeUntil(Func1),不過takeWhile()是當(dāng)Observable發(fā)射的數(shù)據(jù)不滿足條件時(shí)中止Observable的發(fā)射网沾。
//takeWhile:當(dāng)發(fā)射的數(shù)據(jù)等于3時(shí)中止發(fā)射
Observable.just(1, 2, 3, 4, 5)
.takeWhile(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer != 3;
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.e("rx_test", "takeWhile:" + integer);
}
});
輸出結(jié)果:
takeWhile:1
takeWhile:2
原理圖:
Skip
skip(int count)操作符癞蚕,忽略發(fā)射觀測序列的前count項(xiàng)數(shù)據(jù)蕊爵。
//忽略前兩個(gè)小區(qū)數(shù)據(jù)
Observable.from(communities)
.skip(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "skip:忽略前兩個(gè)小區(qū):" + community.getCommunityName());
}
});
輸出結(jié)果:
skip:忽略前兩個(gè)小區(qū):帝豪家園
原理圖:
SkipLast
skipLast(int count)操作符辉哥,忽略發(fā)射觀測序列的后count項(xiàng)數(shù)據(jù)。
//忽略后兩個(gè)小區(qū)數(shù)據(jù)
Observable.from(communities)
.skipLast(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "skip:忽略后兩個(gè)小區(qū):" + community.getCommunityName());
}
});
輸出結(jié)果:
忽略后兩個(gè)小區(qū):東方花園
原理圖:
SkipUntil
skipUntil操作符攒射,與takeUntil()相反醋旦。訂閱并開始發(fā)射原始Observable,同時(shí)監(jiān)視我們提供的第二個(gè)Observable会放。如果第二個(gè)Observable發(fā)射了一項(xiàng)數(shù)據(jù)或者發(fā)射了一個(gè)終止通知饲齐,skipUntil()返回的Observable才會(huì)開始發(fā)射數(shù)據(jù),忽略之前的數(shù)據(jù)項(xiàng)咧最。
原理圖:
SkipWhile
skipWhile操作符捂人,與takeWhile相反,當(dāng)Observable發(fā)射的數(shù)據(jù)不滿足條件時(shí)才開始發(fā)射數(shù)據(jù)矢沿,忽略之前的數(shù)據(jù)項(xiàng)滥搭。
原理圖:
Debounce
debounce操作符有兩種類型的入?yún)ⅰ?/p>
1.debounce(long, TimeUnit)
過濾由Observable發(fā)射的速率過快的數(shù)據(jù),起到限流的作用捣鲸。第一個(gè)參數(shù)為限流時(shí)間瑟匆,第二個(gè)參數(shù)為時(shí)間單位。
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
try {
for (int i = 1; i < 10; i++) {
subscriber.onNext(i);
Thread.sleep(i * 100); //分別延時(shí)100栽惶,200愁溜,300疾嗅,400,500......900ms發(fā)射數(shù)據(jù)
}
subscriber.onCompleted();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).subscribeOn(Schedulers.newThread())
.debounce(400, TimeUnit.MILLISECONDS)
.subscribe(new Observer<Integer>() {
@Override
public void onCompleted() {
Log.e("rx_test", "debounce:" + "onCompleted");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.e("rx_test", "debounce:" + integer);
}
});
輸出結(jié)果:
debounce:5
debounce:6
debounce:7
debounce:8
debounce:9
debounce:onCompleted
由輸出結(jié)果可以看出由于設(shè)定限流時(shí)間為500ms冕象,所以1-4并沒有被發(fā)射而是被過濾了代承。
注意:如果源Observable產(chǎn)生的最后一個(gè)結(jié)果在限流時(shí)間內(nèi)內(nèi)調(diào)用了onCompleted,那么通過debounce操作符也會(huì)把這個(gè)結(jié)果提交給訂閱者渐扮。
原理圖:
2.debounce(Func1)
根據(jù)Func1的call方法中的函數(shù)來過濾次泽。Func1中的中的call方法返回了一個(gè)臨時(shí)的Observable,如果原始的Observable在發(fā)射一個(gè)新的數(shù)據(jù)時(shí)席爽,上一個(gè)數(shù)據(jù)根據(jù)Func1的call方法生成的臨時(shí)Observable還沒結(jié)束意荤,那么上一個(gè)數(shù)據(jù)就會(huì)被過濾掉。
原理圖:
Distinct
1.distinct()
只允許還沒有發(fā)射過的數(shù)據(jù)通過只锻,達(dá)到去除序列中重復(fù)項(xiàng)的作用玖像。
//去除重復(fù)數(shù)字
Observable.just(1, 2, 2, 3, 4, 5, 6, 6, 6, 7)
.distinct()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.e("rx_test", "distinct:去重:" + integer);
}
});
輸出結(jié)果:
distinct:去重:1
distinct:去重:2
distinct:去重:3
distinct:去重:4
distinct:去重:5
distinct:去重:6
distinct:去重:7
由輸出結(jié)果可見有重復(fù)的2和6都被過濾了。
原理圖:
2.distinct(Func1)
根據(jù)Func1中的call方法進(jìn)行去重齐饮,call方法會(huì)根據(jù)Observable發(fā)射的值生成一個(gè)Key捐寥,然后比較這個(gè)key來判斷兩個(gè)數(shù)據(jù)是否相同,如果判定為重復(fù)則會(huì)和distinct()一樣過濾掉重復(fù)的數(shù)據(jù)項(xiàng)祖驱。
//根據(jù)某屬性去重握恳,去除各小區(qū)大小相同的房源
Observable.from(communities)
.flatMap(new Func1<Community, Observable<House>>() {
@Override
public Observable<House> call(Community community) {
return Observable.from(community.getHouses());
}
})
.distinct(new Func1<House, Float>() {
@Override
public Float call(House house) {
return house.getSize();
}
})
.subscribe(new Action1<House>() {
@Override
public void call(House house) {
Log.e("rx_test", "distinct(Func1):去重:" + house.getCommunityName() + "小區(qū),大修嗥А:" + house.getSize());
}
});
輸出結(jié)果:
distinct(Func1):去重:東方花園小區(qū)乡洼,大小:105.6
distinct(Func1):去重:東方花園小區(qū)匕坯,大惺恰:144.8
distinct(Func1):去重:馬德里春天小區(qū),大懈鹁:88.6
distinct(Func1):去重:馬德里春天小區(qū)锹雏,大小:123.4
distinct(Func1):去重:帝豪家園小區(qū)术奖,大薪缸瘛:188.7
distinct(Func1):去重:帝豪家園小區(qū),大胁杉恰:56.4
DistinctUntilChanged
1.distinctUntilChanged()
通過當(dāng)前數(shù)據(jù)項(xiàng)與前一項(xiàng)是否相同來進(jìn)行去重佣耐。
//向前去重復(fù)數(shù)據(jù)
Observable.just(1, 2, 2, 3, 4, 2, 3, 5, 5)
.distinctUntilChanged()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.e("rx_test", "distinctUntilChanged:向前去重:" + integer);
}
});
輸出結(jié)果:
distinctUntilChanged:向前去重:1
distinctUntilChanged:向前去重:2
distinctUntilChanged:向前去重:3
distinctUntilChanged:向前去重:4
distinctUntilChanged:向前去重:2
distinctUntilChanged:向前去重:3
distinctUntilChanged:向前去重:5
原理圖:
2.distinctUntilChanged(Func1)
與distinct(Func1)類似,根據(jù)Func1中call方法產(chǎn)生一個(gè)key來判斷相鄰兩個(gè)數(shù)據(jù)項(xiàng)是否相同挺庞。
//根據(jù)某屬性向前去重晰赞,去除各小區(qū)名相同的房源
Observable.from(communities)
.flatMap(new Func1<Community, Observable<House>>() {
@Override
public Observable<House> call(Community community) {
return Observable.from(community.getHouses())
.distinctUntilChanged(new Func1<House, String>() {
@Override
public String call(House house) {
return house.getCommunityName();
}
});
}
})
.subscribe(new Action1<House>() {
@Override
public void call(House house) {
Log.e("rx_test", "distinctUntilChanged(Func1):向前去重:" + house.getCommunityName() + "小區(qū),大小:" + house.getSize());
}
});
輸出結(jié)果:
distinctUntilChanged(Func1):向前去重:東方花園小區(qū)掖鱼,大腥蛔摺:105.6
distinctUntilChanged(Func1):向前去重:馬德里春天小區(qū),大邢返病:88.6
distinctUntilChanged(Func1):向前去重:帝豪家園小區(qū)郭怪,大兄窠贰:188.7
ElementAt
elementAt(int index)操作符意乓,獲取觀測序列中第index項(xiàng)索引赏迟,并作為唯一數(shù)據(jù)發(fā)射給觀察者,index索引從0開始妥凳。
Observable.from(communities)
.elementAt(1)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "elementAt:第二個(gè)小區(qū):" + community.getCommunityName());
}
});
輸出結(jié)果:
elementAt:第二個(gè)小區(qū):馬德里春天
原理圖:
First
1.first()
只發(fā)射觀測序列中的第一個(gè)數(shù)據(jù)項(xiàng)竟贯。
Observable.from(communities)
.first()
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "first:" + community.getCommunityName());
}
});
輸出結(jié)果:
first:東方花園
原理圖:
2.first(Func1)
根據(jù)Func1中call方法的條件,發(fā)射符合條件的第一個(gè)數(shù)據(jù)項(xiàng)逝钥。
//過濾出第一個(gè)小區(qū)名為馬德里春天的小區(qū)
Observable.from(communities)
.first(new Func1<Community, Boolean>() {
@Override
public Boolean call(Community community) {
return "馬德里春天".equals(community.getCommunityName());
}
})
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "first(Func1):" + community.getCommunityName());
}
});
輸出結(jié)果:
first(Func1):馬德里春天
Last
1.last()
只發(fā)射觀測序列中的最后一個(gè)數(shù)據(jù)項(xiàng)屑那。
//發(fā)送最后一個(gè)數(shù)據(jù)項(xiàng)
Observable.from(communities)
.last()
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "last:" + community.getCommunityName());
}
});
輸出結(jié)果:
last:帝豪家園
原理圖:
2.last(Func1)
根據(jù)Func1中call方法的條件,發(fā)射符合條件的最后一個(gè)數(shù)據(jù)項(xiàng)艘款。
//發(fā)送符合條件的最后一個(gè)數(shù)據(jù)項(xiàng):過濾最后一個(gè)小區(qū)名為馬德里春天的房源
Observable.from(communities)
.flatMap(new Func1<Community, Observable<House>>() {
@Override
public Observable<House> call(Community community) {
return Observable.from(community.getHouses());
}
})
.last(new Func1<House, Boolean>() {
@Override
public Boolean call(House house) {
return "馬德里春天".equals(house.getCommunityName());
}
})
.subscribe(new Action1<House>() {
@Override
public void call(House house) {
Log.e("rx_test", "last:" + house.getCommunityName() + "小區(qū)持际,大小:" + house.getSize());
}
});
輸出結(jié)果:
last:馬德里春天小區(qū)哗咆,大兄┯:88.6
總結(jié)
到此,本篇關(guān)于RxJava的常用過濾類操作符就講解完畢了晌柬,下一篇我們將一起研究RxJava的四類操作符中的組合操作符都有哪些以及如何使用姥份。
技術(shù)渣一枚,有寫的不對的地方歡迎大神們留言指正空繁,有什么疑惑或者建議也可以在我Github上RxJavaDemo項(xiàng)目Issues中提出殿衰,我會(huì)及時(shí)回復(fù)。
附上RxJavaDemo的地址:
RxJavaDemo