java 如何使用 switchIfEmpty RxJava

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39078029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:04:45  来源:igfitidea点击:

How to use switchIfEmpty RxJava

javaandroidrx-java

提问by blackpanther

The logic here is that if the ratings in the database are empty, then I want to get them from the API. I have the following code:

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

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

The getRatingsFromDB()call returns List<SettingRating>, but the API call returns Observable<List<SettingRating>>.

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

However, when I unit test this, when I pass an empty list from the database call, it does not execute the API call. Can someone pls help me in this matter. This is my unit test code:

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

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

settingsParentalPresenter.onViewLoad(false);

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

回答by blackpanther

As @Kiskae mentioned, it's the fact that I am confusing an empty list with an empty Observable. Therefore, I have used the following which is what I want:

正如@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);
}

回答by Kiskae

Observable#toList()returns a single element. If the observable from which it gets its elements is empty, it will emit an empty list. So by definition the observable will never be empty after calling toList().

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

回答by Kalpesh Patel

switchIfEmptywill only be called when your observer completes without emitting any items. Since you are doing toListit will emit list object. Thats why your switchIfEmptyis never getting called.

switchIfEmpty只有当您的观察者完成而不发出任何项目时才会被调用。既然你这样做了,toList它就会发出列表对象。这就是为什么您switchIfEmpty永远不会被调用的原因。

If you want to get data from cache and fallback to your api if cache is empty, use concatealong with firstor takeFirstoperator.

如果您想从缓存中获取数据并在缓存为空时回退到您的 api,请concatefirsttakeFirst运算符一起使用。

For example:

例如:

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

回答by Simon Baslé

Building on answer by @kiskae, your use of a toList()emits the elements aggregated as a single List.

基于@kiskae 的回答,您使用 atoList()会发出聚合为单个List.

There is an alternative to the use of Observable.just()+ a flatMaphere.

这里有一个使用Observable.just()+ a的替代方法flatMap

Observable.fromwill iterate over the list returned by your service and emit each individual items, so an Observable<Rating>. If said list is empty, it naturally produces an empty Observable. Your API call also produces an Observable<Rating>, and in both cases you want to reaggregate that back into a List<Rating>for further processing.

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

So just move the toList()from your original code down one line, after the switchIfEmptycalling the API:

因此toList(),在switchIfEmpty调用 API之后,只需将原始代码中的代码向下移动一行:

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

Granted, that solution may produce a bit more garbage (as the db's Listis turned into an Observablejust to be turned into a new Listlater on).

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