RxJava2复杂用例

时间:2018-07-26 07:04:11

标签: rx-java2

首先,我有一个API下载一个包含附件列表的Article对象:

// retrofit article endpoint
@GET("/article")
Single<Article> getArticle();

// article class
public class Article {
    List<? extends Attachment> attachments;
}

但是,附件具有不同的子类,例如Video,TextFile等。 对于TextFile,它只有一个ID,而文本内容需要使用ID从另一个API下载:

// retrofit text content endpoint
@GET("/text/{id}")
Single<String> getTextContent(@Path("id") int textFileId);

// text file class
public class TextFile extends Attachment {

    // we get id from getArticle API and it's used for download content
    private int id;

    // we get content from getTextContent API
    private String content;

    // getters, setters...
}

下载附件列表中每个TextFile对象的文本内容字符串后,需要使用将其设置回相应的TextFile对象列表的方法,最后返回要显示的Article对象。

当前,我正在做的是:

public Single<Article> getArticleForView() {
    return service.getArticle()
             .somehowChainWithGetTextFileWithContent?
}

// method to download text content and set it to TextFile object in the attachment list
private Flowable<TextFile> getTextFileWithContent(List<? extends Attachment> attachments) {

    return Flowable.fromIterable(attachments)

            // filter out non TextFile attachments
            .filter(attachment -> attachment instanceof TextFile)

            // download text content and set to TextFile
            .concatMap(attachment -> {

                TextFile textFile = (TextFile) attachment;

                return service.getTextContent(textFile.getId())
                        .map(textContent -> {
                            textFile.setContent(textContent);
                            return textFile;
                        })
                        .toFlowable();
            });
}

所以,我想知道是否有任何RxJava2运算符可以链接这些调用以适合我的用例?任何帮助将不胜感激。


编辑: 所以这是我最终得到的解决方案:

首先,我将Article类中的Attachment列表更改为set,所以我不必担心将更新的TextFiles合并到Article对象中。但是显然我需要重写Attachment Class中的equals()方法以通过id保持唯一性。

// article class
public class Article {
    Set<? extends Attachment> attachments;
}

然后,我创建了一个方法来获取TextFile对象(不包含内容)并返回更新后的TextFile对象的Single:

private Single<TextFile> getTextFileWithContent(TextFile textFile) {
    return service.getTextContent(textFile.getId())
            .map(content -> {
                textFile.setContent(content);
                return textFile;
            });
}

然后另一个方法接受一个Article对象,并返回一个Single>,我将其链接到getArticle()调用:

private Single<Set<TextFile>> getArticleTextFileDetails(Article article) {
    Set<Attachment> attachments = article.getAttachments();
    if(attachments == null || attachments.isEmpty()) {
        return Single.just(Collections.emptySet());
    }

    // initial item for collectInto operator
    Set<TextFile> updatedTextFiles = new HashSet<>();

    return Flowable.fromIterable(attachments)

            // filter out non TextFile attachments
            .filter(attachment -> attachment instanceof TextFile)

            // download content and set to TextFile
            .flatMapSingle(this::getTextFileWithContent)

            // collect all emits from Flowable into a Single
            .collectInto(updatedTextFiles, Set::add);
}

获得更新的TextFiles集之后,我只需通过flatMap运算符将其与getArticle()方法链接起来即可:

public Single<Article> getArticleForView() {
    return service.getArticle()
            .flatMap(article -> {

                return getArticleTextFileDetails(article)
                        .map(updatedTextFileSet -> {

                            if(!updatedTextFileSet.isEmpty()) {

                                // simply add updated TextFile set to Attachment set
                                // since we already override equals() method in Attachment class
                                 article.addAttachments(updatedTextFileSet);
                            }
                            return article;
                        })
            });
}

0 个答案:

没有答案