当前位置: 代码迷 >> java >> 如何将来自不同可观察值的rx.Observable搜索结果合并为一个可观察值?
  详细解决方案

如何将来自不同可观察值的rx.Observable搜索结果合并为一个可观察值?

热度:33   发布时间:2023-07-25 19:47:35.0

对于我的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<List<SearchResult>>如果RxJava有更好的方法做到这一点,我可以将它们作为单个SearchResult而不是作为List<>发出。

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

让我们一次完成一个步骤。

为了使它更通用,可以说您有一个对象(= SearchResult)和一个枚举(= Content)称为anEnum。

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

第一步: Observable<List<Object>>Observable<ArrayListMultimap<anEnum, Object>>

    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;
    });
    }

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

第二步:为所有数据创建可观察值,假设您有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);

第三步: 它们到一个流中(如果顺序对您来说很重要,您也可以使用 )

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

第四步: 它们为一个列表,我们将使用第一个列表作为所有列表

        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);

doSomething所在位置: private void doSomething(ArrayListMultimap<anEnum, Object> list)

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

假设针对每种搜索类型将单个Observable拆分为单独的Observable ,则可以使用或将所有结果再次收集到单个Observable 这将使您能够并行运行搜索,如果您愿意,也可以运行单个搜索。

例如,您可以将两个Observable串联起来,如下所示:

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

可观察到的result将发出1, 2, 3, 4, 5, 6