前言
上一篇文章我們學習了轉換類操作符,本篇我們將一起來學習RxJava過濾類操作符。過濾操作符主要是用來對事件資料進行過濾與篩選,只返回滿足條件的資料,一起來看下都有哪些。
過濾操作符
Filter
filter操作符,按照一定的約束條件過濾序列中我們不想要的資料,只返回滿足條件的資料給觀察者。
//結合flatmap,過濾出各小區中房源大小大於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() + "小區,大小:" + house.getSize());
}
});複製程式碼
由程式碼可見,我們需要new一個Func1物件給filter(),Func1<House, Boolean>()
中第一個是由觀測序列傳入資料的型別,第二個是返回是否過濾的Boolean物件。滿足filter()的條件則返回true,否則返回false。並將返回為true的資料發射給觀察者。
輸出結果:
filter:大於120平的房子:東方花園小區,大小:144.8
filter:大於120平的房子:東方花園小區,大小:144.8
filter:大於120平的房子:馬德里春天小區,大小:123.4
filter:大於120平的房子:馬德里春天小區,大小:123.4
filter:大於120平的房子:帝豪家園小區,大小:188.7
filter:大於120平的房子:帝豪家園小區,大小:188.7
filter:大於120平的房子:帝豪家園小區,大小:188.7複製程式碼
原理圖:
實際專案開發中,filter操作符可用來過濾資料集合中的null值,方便實用。
Take
take(int count)操作符,可用來擷取觀測序列中前count個元素併發射。
//take:獲取前兩個小區名
Observable.from(communities)
.take(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "take:前兩個小區:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
take:前兩個小區:東方花園
take:前兩個小區:馬德里春天複製程式碼
原理圖:
TakeLast
takeLast(int count)操作符,顧名思義,擷取觀測序列中後count個元素併發射。
//takeLast:獲取後兩個小區名
Observable.from(communities)
.takeLast(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "takeLast:後兩個小區:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
takeLast:後兩個小區:馬德里春天
takeLast:後兩個小區:帝豪家園複製程式碼
原理圖:
TakeUntil
takeUntil操作符有兩種型別的入參。
1.takeUntil(Observable)
訂閱並開始發射原始Observable,同時監視我們提供的第二個Observable。如果第二個Observable發射了一項資料或者發射了一個終止通知,takeUntil()返回的Observable會停止發射原始Observable並終止。
//observableA每300ms發射一個Long型自增資料
//observableB每800ms發射一個Long型自增資料
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);
}
});複製程式碼
輸出結果:
takeUntil(Observable):onNext:0
takeUntil(Observable):onNext:1
takeUntil(Observable):onCompleted複製程式碼
由輸出結果可看出,訂閱之後,observableA依次發射0,1之後就發射onCompleted標記停止了。這是由於observableA每300ms發射一次,當發射完1後,時間已過去600ms,到800ms時observableB開始發射資料,takeUntil起作用則中斷了observableA的發射。
原理圖:
2.takeUntil(Func1)
通過傳入的Func1中的call()方法判斷是否中止發射資料。
//takeUntil:與flatmap結合過濾直到房價大於500時中斷當前小Observable發射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時中斷髮射:" + house.getCommunityName() + "小區,房價:" + house.getPrice());
}
});複製程式碼
輸出結果:
takeUntil(Func1):大於500時中斷髮射:東方花園小區,房價:200
takeUntil(Func1):大於500時中斷髮射:東方花園小區,房價:520複製程式碼
原理圖:
TakeWhile
takeWhile操作符,類似於takeUntil(Func1),不過takeWhile()是當Observable發射的資料不滿足條件時中止Observable的發射。
//takeWhile:當發射的資料等於3時中止發射
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);
}
});複製程式碼
輸出結果:
takeWhile:1
takeWhile:2複製程式碼
原理圖:
Skip
skip(int count)操作符,忽略發射觀測序列的前count項資料。
//忽略前兩個小區資料
Observable.from(communities)
.skip(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "skip:忽略前兩個小區:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
skip:忽略前兩個小區:帝豪家園複製程式碼
原理圖:
SkipLast
skipLast(int count)操作符,忽略發射觀測序列的後count項資料。
//忽略後兩個小區資料
Observable.from(communities)
.skipLast(2)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "skip:忽略後兩個小區:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
忽略後兩個小區:東方花園複製程式碼
原理圖:
SkipUntil
skipUntil操作符,與takeUntil()相反。訂閱並開始發射原始Observable,同時監視我們提供的第二個Observable。如果第二個Observable發射了一項資料或者發射了一個終止通知,skipUntil()返回的Observable才會開始發射資料,忽略之前的資料項。
原理圖:
SkipWhile
skipWhile操作符,與takeWhile相反,當Observable發射的資料不滿足條件時才開始發射資料,忽略之前的資料項。
原理圖:
Debounce
debounce操作符有兩種型別的入參。
1.debounce(long, TimeUnit)
過濾由Observable發射的速率過快的資料,起到限流的作用。第一個引數為限流時間,第二個引數為時間單位。
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); //分別延時100,200,300,400,500......900ms發射資料
}
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);
}
});複製程式碼
輸出結果:
debounce:5
debounce:6
debounce:7
debounce:8
debounce:9
debounce:onCompleted複製程式碼
由輸出結果可以看出由於設定限流時間為500ms,所以1-4並沒有被髮射而是被過濾了。
注意:如果源Observable產生的最後一個結果在限流時間內內呼叫了onCompleted,那麼通過debounce操作符也會把這個結果提交給訂閱者。
原理圖:
2.debounce(Func1)
根據Func1的call方法中的函式來過濾。Func1中的中的call方法返回了一個臨時的Observable,如果原始的Observable在發射一個新的資料時,上一個資料根據Func1的call方法生成的臨時Observable還沒結束,那麼上一個資料就會被過濾掉。
原理圖:
Distinct
1.distinct()
只允許還沒有發射過的資料通過,達到去除序列中重複項的作用。
//去除重複數字
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);
}
});複製程式碼
輸出結果:
distinct:去重:1
distinct:去重:2
distinct:去重:3
distinct:去重:4
distinct:去重:5
distinct:去重:6
distinct:去重:7複製程式碼
由輸出結果可見有重複的2和6都被過濾了。
原理圖:
2.distinct(Func1)
根據Func1中的call方法進行去重,call方法會根據Observable發射的值生成一個Key,然後比較這個key來判斷兩個資料是否相同,如果判定為重複則會和distinct()一樣過濾掉重複的資料項。
//根據某屬性去重,去除各小區大小相同的房源
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() + "小區,大小:" + house.getSize());
}
});複製程式碼
輸出結果:
distinct(Func1):去重:東方花園小區,大小:105.6
distinct(Func1):去重:東方花園小區,大小:144.8
distinct(Func1):去重:馬德里春天小區,大小:88.6
distinct(Func1):去重:馬德里春天小區,大小:123.4
distinct(Func1):去重:帝豪家園小區,大小:188.7
distinct(Func1):去重:帝豪家園小區,大小:56.4複製程式碼
DistinctUntilChanged
1.distinctUntilChanged()
通過當前資料項與前一項是否相同來進行去重。
//向前去重複資料
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);
}
});複製程式碼
輸出結果:
distinctUntilChanged:向前去重:1
distinctUntilChanged:向前去重:2
distinctUntilChanged:向前去重:3
distinctUntilChanged:向前去重:4
distinctUntilChanged:向前去重:2
distinctUntilChanged:向前去重:3
distinctUntilChanged:向前去重:5複製程式碼
原理圖:
2.distinctUntilChanged(Func1)
與distinct(Func1)類似,根據Func1中call方法產生一個key來判斷相鄰兩個資料項是否相同。
//根據某屬性向前去重,去除各小區名相同的房源
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() + "小區,大小:" + house.getSize());
}
});複製程式碼
輸出結果:
distinctUntilChanged(Func1):向前去重:東方花園小區,大小:105.6
distinctUntilChanged(Func1):向前去重:馬德里春天小區,大小:88.6
distinctUntilChanged(Func1):向前去重:帝豪家園小區,大小:188.7複製程式碼
ElementAt
elementAt(int index)操作符,獲取觀測序列中第index項索引,並作為唯一資料發射給觀察者,index索引從0開始。
Observable.from(communities)
.elementAt(1)
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "elementAt:第二個小區:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
elementAt:第二個小區:馬德里春天複製程式碼
原理圖:
First
1.first()
只發射觀測序列中的第一個資料項。
Observable.from(communities)
.first()
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "first:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
first:東方花園複製程式碼
原理圖:
2.first(Func1)
根據Func1中call方法的條件,發射符合條件的第一個資料項。
//過濾出第一個小區名為馬德里春天的小區
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());
}
});複製程式碼
輸出結果:
first(Func1):馬德里春天複製程式碼
Last
1.last()
只發射觀測序列中的最後一個資料項。
//傳送最後一個資料項
Observable.from(communities)
.last()
.subscribe(new Action1<Community>() {
@Override
public void call(Community community) {
Log.e("rx_test", "last:" + community.getCommunityName());
}
});複製程式碼
輸出結果:
last:帝豪家園複製程式碼
原理圖:
2.last(Func1)
根據Func1中call方法的條件,發射符合條件的最後一個資料項。
//傳送符合條件的最後一個資料項:過濾最後一個小區名為馬德里春天的房源
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() + "小區,大小:" + house.getSize());
}
});複製程式碼
輸出結果:
last:馬德里春天小區,大小:88.6複製程式碼
總結
到此,本篇關於RxJava的常用過濾類操作符就講解完畢了,下一篇我們將一起研究RxJava的四類操作符中的組合操作符都有哪些以及如何使用。
技術渣一枚,有寫的不對的地方歡迎大神們留言指正,有什麼疑惑或者建議也可以在我Github上RxJavaDemo專案Issues中提出,我會及時回覆。
附上RxJavaDemo的地址:
RxJavaDemo