如何使用switchIfEmpty RxJava

时间:2016-08-22 11:10:04

标签: java android rx-java

这里的逻辑是,如果数据库中的评级为空,那么我想从API中获取它们。我有以下代码:

Observable.from(settingsRatingRepository.getRatingsFromDB())
            .toList()
            .switchIfEmpty(settingsRatingRepository.getSettingsRatingModulesFromAPI())
            .compose(schedulerProvider.getSchedulers())
            .subscribe(ratingsList -> {
                view.loadRatingLevels(ratingsList, hideLocks);
            }, this::handleError);

getRatingsFromDB()调用返回List<SettingRating>,但API调用返回Observable<List<SettingRating>>

但是,当我对它进行单元测试时,当我从数据库调用中传递一个空列表时,它不会执行API调用。有人可以帮我解决这个问题。这是我的单元测试代码:

when(mockSettingsRatingsRepository.getRatingsFromDB()).thenReturn(Collections.emptyList());
List<SettingsRating> settingsRatings = MockContentHelper.letRepositoryReturnSettingsRatingsFromApi(mockSettingsRatingsRepository);

settingsParentalPresenter.onViewLoad(false);

verify(mockView).loadRatingLevels(settingsRatings, false);

4 个答案:

答案 0 :(得分:6)

正如@Kiskae所提到的那样,事实是我将空列表与空Observable混淆。因此,我使用了以下我想要的东西:

public void onViewLoad(boolean hideLocks) {
    Observable.just(settingsRatingRepository.getRatingsFromDB())
            .flatMap(settingsRatings -> {
                if (settingsRatings.isEmpty()) {
                    return settingsRatingRepository.getSettingsRatingModules();
                } else {
                    return Observable.just(settingsRatings);
                }
            })
            .compose(schedulerProvider.getSchedulers())
            .subscribe(ratingsList -> {
                view.loadRatingLevels(ratingsList, hideLocks);
            }, this::handleError);
}

答案 1 :(得分:1)

Observable#toList()返回单个元素。如果获取其元素的observable为空,则它将发出一个空列表。因此,根据定义,在调用toList()后,observable将永远不会为空。

答案 2 :(得分:1)

switchIfEmpty只有在您的观察者完成而不发出任何物品时才会被调用。 由于您正在执行toList,它将发出列表对象。这就是为什么你的switchIfEmpty永远不会被召唤的原因。

如果要在缓存为空时从缓存中获取数据并回退到api,请使用concate以及firsttakeFirst运算符。

例如:

Observable.concat(getDataFromCache(), getDataFromApi())
            .first(dataList -> !dataList.isEmpty());

答案 3 :(得分:0)

根据@kiskae的回答,您使用toList()会将汇总的元素作为单个List发出。

此处可以使用Observable.just() + a flatMap替代。

Observable.from将遍历您的服务返回的列表并发出每个单独的项目,因此Observable<Rating>Observable。如果所述列表为空,则自然会产生空Observable<Rating>。您的API调用也会产生List<Rating>,在这两种情况下,您都希望将其重新聚合回toList()以进行进一步处理。

switchIfEmpty调用API之后,只需将原始代码中的Observable.from(settingsRatingRepository.getRatingsFromDB()) .switchIfEmpty(settingsRatingRepository.getSettingsRatingModulesFromAPI()) .toList() .compose(schedulerProvider.getSchedulers()) .subscribe(ratingsList -> { view.loadRatingLevels(ratingsList, hideLocks); }, this::handleError); 向下移动一行:

List

当然,该解决方案可能会产生更多垃圾(因为数据库Observable变成了List只是为了稍后变成新的failed()