【问题标题】:How to use switchIfEmpty RxJava如何使用 switchIfEmpty RxJava
【发布时间】:2016-08-22 11:10:04
【问题描述】:

这里的逻辑是,如果数据库中的评分是空的,那么我想从 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);

【问题讨论】:

    标签: java android rx-java


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 好吧,如果我使用 Observable.just() 会怎样。 getRatingsFromDB() 方法返回 List&lt;SettingRating&gt;,但 API 调用返回 Observable&lt;List&lt;SettingRating&gt;&gt;
      • 如果列表也是空的,使用Observable.just() 然后Observable.filter() 来清空observable,让它按照你想要的方式运行。所以Observable.just(getRatingsFromDB()).filter(list -&gt; !list.isEmpty())
      【解决方案3】:

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

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

      例如:

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

      【讨论】:

        【解决方案4】:

        基于@kiskae 的回答,您使用toList() 会发出聚合为单个List 的元素。

        这里可以使用Observable.just() + flatMap 的替代方法。

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

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

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

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

        【讨论】:

        • 我不认为这可以作为替代品,因为如果我没看错,settingsRatingRepository.getSettingsRatingModulesFromAPI() 会返回Observable&lt;List&lt;SettingsRating&gt;&gt;
        • 啊,如果是这样的话,我很糟糕
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-07
        • 2020-02-27
        • 1970-01-01
        • 2017-01-05
        • 2015-09-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多