Android RxJava平面映射链接请求
我正在使用RxJAva对一个获取Rss提要的应用程序进行改造,但Rss并不包含所有信息,因此我使用jsoup解析每个项目链接,以检索图像和文章描述。现在我这样使用它:Android RxJava平面映射链接请求,android,retrofit,rx-java,chaining,flatmap,Android,Retrofit,Rx Java,Chaining,Flatmap,我正在使用RxJAva对一个获取Rss提要的应用程序进行改造,但Rss并不包含所有信息,因此我使用jsoup解析每个项目链接,以检索图像和文章描述。现在我这样使用它: public Observable<Rss> getDumpData() { return newsAppService.getDumpData() .flatMap(rss -> Observable.from(rss.channel.items) .ob
public Observable<Rss> getDumpData() {
return newsAppService.getDumpData()
.flatMap(rss -> Observable.from(rss.channel.items)
.observeOn(Schedulers.io())
.flatMap(Checked.f1(item -> Observable.just(Jsoup.connect(item.link).get())
.observeOn(Schedulers.io())
.map(document -> document.select("div[itemprop=image] > img").first())
.doOnNext(element -> item.image = element.attr("src"))
)))
.defaultIfEmpty(rss)
.ignoreElements()
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread());
}
公共可观测getDumpData(){
返回newsAppService.getDumpData()
.flatMap(rss->Observable.from(rss.channel.items)
.observeOn(Schedulers.io())
.flatMap(Checked.f1(item->Observable.just(Jsoup.connect(item.link).get())
.observeOn(Schedulers.io())
.map(document->document.select(“div[itemprop=image]>img”).first()
.doOnNext(element->item.image=element.attr(“src”))
)))
.defaultIfEmpty(rss)
.ignoreElements()
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread());
}
我在这一行得到一个错误:defaultIfEmpty(rss)
它无法识别平面地图的rss。当我移动flatmap括号中的
defaultIfEmpty(rss)
时,我有另一个错误,即返回类型必须更改为元素。他们有什么解决办法吗 不能将一个RxJava
参数(flatMap
lambda参数)的内部参数与另一个运算符参数(defaultIfEmpty
)混合使用
首先,创建一个helper函数以保持主反应流更干净:
private Observable<List<Item>> getDetails(List<Item> items) {
return Observable.from(items)
.observeOn(Schedulers.io())
.flatMap(Checked.f1(item ->
Observable.zip(
Observable.just(item),
Observable.just(Jsoup.connect(item.link).get())
.observeOn(Schedulers.io())
.map(document -> document.select("div[itemprop=image] > img").first()),
(itemInner, element) -> {
itemInner.image = element.attr("src");
return itemInner;
}
)
))
.toList();
}
private observeable getDetails(列表项){
可观察的返回。来自(项目)
.observeOn(Schedulers.io())
.flatMap(选中.f1(项目->
可观察的.zip(
可观察。仅(项目),
Observable.just(Jsoup.connect(item.link.get())
.observeOn(Schedulers.io())
.map(document->document.select(“div[itemprop=image]>img”).first(),
(项目内部,元素)->{
itemInner.image=element.attr(“src”);
返回项目内部;
}
)
))
.toList();
}
然后重新格式化主功能:
newsAppService.getDumpData()
.flatMap(rss ->
Observable.zip(
Observable.<Rss>just(rss),
getDetails(rss.channel.items),
(rssInner, items) -> {
rssInner.channel.items = items;
return rss;
}).onErrorResumeNext((throwable -> Observable.just(rss))
)
)
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread());
newsAppService.getDumpData()
.flatMap(rss->
可观察的.zip(
可观察。公正(rss),
获取详细信息(rss.channel.items),
(罪人,物品)->{
rssInner.channel.items=项目;
返回rss;
}).onErrorResumeNext((可丢弃->可观察的.just(rss))
)
)
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread());
希望我正确地瞄准了你。它可能不起作用,因为我无法测试它,但是我希望你能理解。我使用
.zip
的原因在于,您不能失去对当前解析的项的引用
或rss
首先,您需要摆脱与observeOn的所有并发,并使用subscribeOn
.observeOn(Schedulers.io())
请考虑使用AndroidScheduler的观察,如果要将数据从另一个线程同步回事件循环。通常,您会在订阅observeOn之前使用observeOn,以便同步回ui循环并更改ui信息
.observeOn(AndroidSchedulers.mainThread())
其次,不建议对管道中的对象进行变异。每次都应该返回一个新对象
.doOnNext(element -> item.image = element.attr("src"))
考虑到前两点,我试图重构您的解决方案。我使用的是RxJava2-RC5
flatMap操作符有许多重载。其中一个函数提供了将传入值和创建值压缩在一起的函数
Observable<Rss> rssItemObservable = newsService.getDumpData()
.flatMap(rss -> getRssItemInformation(rss).subscribeOn(Schedulers.io()),
(r, rItemList) -> {
Rss rInterim = new Rss();
rInterim.items = rItemList;
return rInterim;
});
Observable rssItemObservable=newservice.getDumpData()
.flatMap(rss->getRssItemInformation(rss).subscribeOn(Schedulers.io()),
(r,rItemList)->{
Rss-rInterim=新的Rss();
rInterim.items=rItemList;
返回rInterim;
});
用于检索Rss中每个项目的信息的帮助方法。请考虑使用最大并发的超载,因为默认情况下它会同时订阅每个流。因此flatMap将创建许多http请求
private Observable<List<RssItem>> getRssItemInformation(Rss rss) {
return Observable.fromIterable(rss.items)
.flatMap(rssItem -> getImageUrl(rssItem).subscribeOn(Schedulers.io()), (rItem, img) -> {
RssItem item = new RssItem();
printCurrentThread("merge1");
item.image = img;
item.link = rItem.link;
return item;
}).toList().toObservable();
}
私有可观察getRssItemInformation(Rss){
返回Observable.fromIterable(rss.items)
.flatMap(rssItem->getImageUrl(rssItem).subscribeOn(Schedulers.io()),(rItem,img)->{
RssItem item=新的RssItem();
printCurrentThread(“合并1”);
item.image=img;
item.link=rItem.link;
退货项目;
}).toList().toObservable();
}
用于检索图像url的帮助方法。返回observable并不是对并发性的固执己见。如果发生错误,将返回一个空字符串作为默认值
private Observable<String> getImageUrl(String link) {
return Observable.fromCallable(() -> Jsoup.connect(link).get())
.map(document -> document.select("div[itemprop=image] > img").first())
.map(element -> element.attr("src"))
.onErrorResumeNext(throwable -> {
return Observable.just("");
});
}
私有可观察getImageUrl(字符串链接){
返回Observable.fromCallable(()->Jsoup.connect(link.get())
.map(document->document.select(“div[itemprop=image]>img”).first()
.map(元素->元素属性(“src”))
.onErrorResumeNext(可丢弃->{
可观察的返回。仅(“”);
});
}
您可以查看github.gist上的完整示例:通过将
flatMap
参数传递到defaultIfEmpty
参数,尝试实现什么?你想捕获一个异常吗?@R.Zagórski它只是为了防止发生错误,它会发出可观察到的源代码。你希望从newsAppService.getDumpData()
或从你的转换中获得图像时会发生错误吗?是的@R.Zagórski我希望它能从转换中抛出一个异常。它工作得很好,但是我不太理解代码,我会阅读zip文档,你救了我