在項(xiàng)目中應(yīng)用RxJava時(shí),遇到了這樣的使用場景:
模擬從服務(wù)器返回了一個(gè)列表。
private Observable<List<String>> getData() {
List<String> stringList = new ArrayList<>();
return Observable.just(stringList);
}
我在處理數(shù)據(jù)時(shí),想判斷一下這個(gè)list是不是空,如果不為空,顯示數(shù)據(jù),如果為空,給用戶一個(gè)沒有數(shù)據(jù)的提示。也就是我們常用的if和else操作。于是我是這樣寫的:
Observable<List<String>> observable = getData();
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
if (strings != null && strings.size() > 0) {
// 顯示數(shù)據(jù)
} else {
// 顯示沒有數(shù)據(jù)的提示
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
// 錯(cuò)誤處理
}
});
Filter
可是我覺得這樣不夠優(yōu)雅不夠RxJava,所以我想到了Filter操作符,能不能用它來幫我完成呢?于是我修改了一下我的代碼。
Observable<List<String>> observable = getData();
observable.filter(new Predicate<List<String>>() {
@Override
public boolean test(@NonNull List<String> strings) throws Exception {
return strings != null && strings.size() > 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
// 顯示數(shù)據(jù)
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
// 錯(cuò)誤處理
}
});
來看一下Filter操作符的官方圖示。

emit only those items from an Observable that pass a predicate test
它會(huì)按照我們給它的條件進(jìn)行過濾,在本例中,只有當(dāng)服務(wù)器返回的list不為null并且有數(shù)據(jù)時(shí),
才會(huì)發(fā)出。這樣的話,可以滿足我有數(shù)據(jù)時(shí)顯示數(shù)據(jù)的需求,但是沒有數(shù)據(jù)時(shí)顯示提示怎么辦呢?
GroupBy
然后我想到了GroupBy這個(gè)操作符。
先看一下官方的圖示吧。

divide an Observable into a set of Observables that each emit a different subset of items from the original Observable
它可以把一個(gè)Observable按照一定的條件分成多個(gè)Observable,在本例中,是否可以分成有數(shù)據(jù)和沒數(shù)據(jù)兩種呢?
我又修改了一下代碼。
Observable<List<String>> observable = getData();
observable.groupBy(new Function<List<String>, Boolean>() {
@Override
public Boolean apply(@NonNull List<String> strings) throws Exception {
return strings != null && strings.size() > 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<GroupedObservable<Boolean, List<String>>>() {
@Override
public void accept(@NonNull GroupedObservable<Boolean, List<String>> groupedObservable) throws Exception {
if (groupedObservable.getKey()) {
groupedObservable.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
// 顯示數(shù)據(jù)
}
});
} else {
groupedObservable.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
// 顯示沒有數(shù)據(jù)的提示
}
});
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
// 錯(cuò)誤處理
}
});
關(guān)鍵在于,有一個(gè)新的GroupedObservable,它有一個(gè)getKey()方法,得到的這個(gè)key就是我們在groupBy操作符中返回的類型,本例中使用的是Boolean類型,根據(jù)不同的業(yè)務(wù)需要,也可以返回Integer或者String等等。
然后在Subscribe的時(shí)候,根據(jù)不同的key值,分為了不同的Observable,滿足了我的需求。
SwitchIfEmpty
最近是實(shí)際使用中,發(fā)現(xiàn)如果使用GroupBy操作符,會(huì)比較復(fù)雜,特別是會(huì)生成了一個(gè)新的groupedObservable。
那么有沒有更好的方法來實(shí)現(xiàn)if-else呢?
來看看另一個(gè)操作符吧,defaultIfEmpty。

Observable<List<String>> observable = getData();
observable
.filter(new Predicate<List<String>>() {
@Override
public boolean test(@NonNull List<String> strings) throws Exception {
return strings != null && strings.size() > 0;
}
})
.defaultIfEmpty(new ArrayList<>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
// 顯示數(shù)據(jù)
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
// 錯(cuò)誤處理
}
});
當(dāng)filter操作符判斷不符合條件不發(fā)射時(shí),可以通過defaultIfEmpty操作符添加一個(gè)默認(rèn)的值。不過好像能做的事情不是很多。
所以我又換了一個(gè)switchIfEmpty操作符。
Observable<List<String>> observable = getData();
observable
.filter(new Predicate<List<String>>() {
@Override
public boolean test(@NonNull List<String> strings) throws Exception {
return strings != null && strings.size() > 0;
}
})
.switchIfEmpty(new Observable<List<String>>() {
@Override
protected void subscribeActual(Observer<? super List<String>> observer) {
List<String> newList = new ArrayList<>();
newList.add("new");
observer.onNext(newList);
observer.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(@NonNull List<String> strings) throws Exception {
// 顯示數(shù)據(jù)
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
// 錯(cuò)誤處理
}
});
效果是一樣的,也是添加了默認(rèn)值,不過能干的事情好像更多了一些。實(shí)際上看一下源碼,發(fā)現(xiàn)其實(shí)差不太多。
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Observable<T> defaultIfEmpty(T defaultItem) {
ObjectHelper.requireNonNull(defaultItem, "defaultItem is null");
return switchIfEmpty(just(defaultItem));
}
只是調(diào)用了switchIfEmpty(just(defaultItem))而已。
不過我發(fā)現(xiàn)了一個(gè)問題,如果我判斷一個(gè)list是不是空,使用filter和switchIfEmpty結(jié)合起來是可以滿足的,但是有些情況會(huì)有問題,看下面這個(gè)例子:
Observable.just(1, 2, 3, 4, 5)
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
return integer % 2 == 0;
}
})
.switchIfEmpty(new Observable<Integer>() {
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
observer.onNext(-1);
observer.onComplete();
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println("integer = [" + integer + "]");
}
});
按照我的設(shè)想,應(yīng)該是-1,2,-1,4,-1這么個(gè)順序,然而結(jié)果卻是2,4。這是為什么呢?
原來如果連續(xù)發(fā)射1,2,3,4,5的時(shí)候,filter操作符會(huì)過濾掉1,3,5,發(fā)射2和4,所以并不為空,所以switchIfEmpty就不會(huì)得到執(zhí)行。比如我們只發(fā)射1,會(huì)被filter過濾掉,然后調(diào)用switchIfEmpty,得到-1;如果我們發(fā)射的是1和2,會(huì)得到2;如果發(fā)射1和3,也只會(huì)得到-1,而不是-1和-1,因?yàn)閟witchIfEmpty只會(huì)調(diào)用一次。