首先,我有一个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;
})
});
}