【问题标题】:How can I combine rx.Observable search results from different observables into a single Observable?如何将来自不同 observable 的 rx.Observable 搜索结果合并到一个 Observable 中?
【发布时间】:2015-08-07 15:12:39
【问题描述】:

对于我的 android 应用,我需要一个 Observable 来聚合来自 7 个不同搜索的结果并作为单个集合发出。

  • 对于最终的发射,我选择了ListMultimap<Content, SearchResult>,其中Content 是搜索结果类型的枚举,SearchResult 是用于显示搜索结果的视图模型界面。

这是我的做法,但是否有我不知道的 RxJava 运算符可以做得更干净?

public Observable<ListMultimap<Content, SearchResult>> getSearchResults(final CharSequence charSequence) {
        return Observable.just(charSequence)
                .map(new Func1<CharSequence, ListMultimap<Content, SearchResult>>() {
                    @Override
                    public ListMultimap<Content, SearchResult> call(CharSequence charSequence) {
                        final String searchTerm = charSequence.toString();

                        final ListMultimap<Content, SearchResult> data =
                                MultimapBuilder.enumKeys(Content.class)
                                        .arrayListValues()
                                        .build();

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getSectionPageSearchResults(searchTerm).toBlocking().first())
                            data.put(Content.SECTION_PAGE, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getAppendixPageSearchResults(searchTerm).toBlocking().first())
                            data.put(Content.APPENDIX_PAGE, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getImageSearchResults(searchTerm, ImageType.FIGURE).toBlocking().first())
                            data.put(Content.FIGURE, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getImageSearchResults(searchTerm, ImageType.TABLE).toBlocking().first())
                            data.put(Content.TABLE, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getImageSearchResults(searchTerm, ImageType.FORM).toBlocking().first())
                            data.put(Content.FORM, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getGlossarySearchResults(searchTerm, GlossaryType.ACRONYMS).toBlocking().first())
                            data.put(Content.ACRONYM, searchResult);

                        for (SearchResult searchResult : SearchBookmarkableRepoImpl.this.getGlossarySearchResults(searchTerm, GlossaryType.DEFINITIONS).toBlocking().first())
                            data.put(Content.DEFINITION, searchResult);

                        return data;
                    }
                });
    }

这是 7 种搜索方法之一的示例方法签名。每个都返回一个 Observable&lt;List&lt;SearchResult&gt;&gt; 如果 RxJava 有更好的方法来做到这一点,我可以将它们作为单独的 SearchResult 而不是 List&lt;&gt; 发出

Observable<List<SearchResult>> getSectionPageSearchResults(final String searchWord)

【问题讨论】:

    标签: java android system.reactive rx-java


    【解决方案1】:

    让我们一步一步来。

    为了更通用,假设您有一个名为 anEnum 的对象 (=SearchResult) 和枚举 (=Content)。

    我已经使用 ArrayListMultimap 进行具体实现,我之前没有使用过,所以如果有更好的方法来添加对象,请这样做。

    第一步:mapObservable&lt;List&lt;Object&gt;&gt;Observable&lt;ArrayListMultimap&lt;anEnum, Object&gt;&gt;

        private Observable<ArrayListMultimap<anEnum, Object>> getMultiListSectionPageSearchResults(final String searchWord, anEnum anEnum) {
        return getSectionPageSearchResults(searchWord).map(objects -> {
            ArrayListMultimap<anEnum, Object> newList = ArrayListMultimap.create();
            for (Object o : objects) {
                newList.put(anEnum, o);
            }
            return newList;
        });
        }
    

    现在您有了所需格式的列表。

    第二步:为所有数据创建 observables,假设你有 4 个

        Observable<ArrayListMultimap<anEnum, Object>> multiList1 = getMultiListSectionPageSearchResults("one", anEnum.ONE);
        Observable<ArrayListMultimap<anEnum, Object>> multiList2 = getMultiListSectionPageSearchResults("two", anEnum.TWO);
        Observable<ArrayListMultimap<anEnum, Object>> multiList3 = getMultiListSectionPageSearchResults("three", anEnum.THREE);
        Observable<ArrayListMultimap<anEnum, Object>> multiList4 = getMultiListSectionPageSearchResults("four", anEnum.FOUR);
    

    第三步:merge他们到一个流(如果订单对你很重要,你也可以使用concat到)

            Observable<ArrayListMultimap<anEnum, Object>> mergedLists = Observable.merge(
                multiList1, multiList2, multiList3, multiList4);
    

    第四步:reduce他们到一个列表,我们将使用第一个列表作为将包含所有的列表

            Observable<ArrayListMultimap<anEnum, Object>> oneList = mergedLists.reduce((l1, l2) -> {
            for (anEnum c : l2.keySet()) {
                for (Object o : l2.get(c)) {
                    l1.put(c, o);
                }
            }
            return l1;
            });
    

    最后一步:使用数据,single() 只是为了确保我们真正得到一个列表

    oneList.single().subscribe(this::doSomething);
    

    在哪里做某事:private void doSomething(ArrayListMultimap&lt;anEnum, Object&gt; list)

    如果您使用常规列表,则转换会容易得多,因为已经有一些方法可以为您做到这一点,例如 l1.addAll(l2) for reduce

    【讨论】:

      【解决方案2】:

      假设您将单个 Observable 拆分为每个搜索类型的单独 Observables,您可以使用 combining operatorsaggregate operators 之一将所有结果再次收集到单个 Observable 中。这将使您能够并行运行搜索,并且如果您愿意,也可以运行单独的搜索。

      例如,您可以像这样连接两个Observables:

      Observable o1 = Observable.just(1, 2, 3);
      Observable o2 = Observable.just(4, 5, 6);
      Observable result = o1.concatWith(o2);
      

      result observable 会发出 1, 2, 3, 4, 5, 6

      【讨论】:

      • 问题是 observable 的结果会发出 6 个不同的项目。我需要在最后将所有这些排放汇总到一个包含我所有结果的 List&lt;Content, SearchResult observable 中,我不知道如何实现这一目标
      • toList() 将收集所有发出的项目并发出这些项目中的单个List。您不能拥有具有两种类型的列表(例如 List&lt;Content, SearchResult&gt;),但您可以将发出的项目 map() 转换为 Pair&lt;Content, SearchResult&gt;,然后将这些对转换为列表。
      • 如果其中一个是 Integer 而另一个是 String 呢?只是(1)和只是(“2”)
      • 在连接它们之前,您总是可以 map() 将其中一个 observables 连接到另一种类型。
      猜你喜欢
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 2017-08-04
      • 2020-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多