RXJava/Kotlin - 链接单个结果为一个
Posted
技术标签:
【中文标题】RXJava/Kotlin - 链接单个结果为一个【英文标题】:RXJava/Kotlin - Chaining Single results in one 【发布时间】:2020-04-29 15:55:59 【问题描述】:我有一个问题,我不知道如何用更好的方法解决它。问题是我正在向 Spotify Web API 请求,并且在某些方法中返回了艺术家图像,而在其他方法中只获得了基本的艺术家信息。
我有这两种方法:
fun getAlbum(albumId: String): Single<SpotifyAlbumDTO>
fun getArtist(artistId: String): Single<SpotifyArtistDTO>
当我获得专辑时,艺术家信息不包含艺术家图片网址。因此,我需要调用 getAlbum() 方法并使用结果获取 artistId,然后调用 getArtist() 方法。
我有以下方法来做所有这些事情:
fun getAlbum(albumId: String): Single<Album>
在这个方法上,我需要调用前两个来返回一个专辑对象(我的域对象)。唯一对我有用的解决方案如下:
fun getAlbum(albumId: String): Single<Album>
return Single.create emitter ->
_spotifyService.getAlbum(albumId).subscribe spotifyAlbum ->
_spotifyService.getArtist(spotifyAlbum.artist.id).subscribe spotifyArtist ->
val artistImage = spotifyArtist.imageUrl
spotifyAlbum.artist.image = artistImage
emitter.onNext(spotifyAlbum.toAlbum())
我认为必须存在另一种更好的方法来做到这一点,而不是在其他订阅中连接订阅调用并创建更深入的调用。我也尝试以下方法:
_spotifyService.getAlbum(albumId).flatMap spotifyAlbum ->
_spotifyService.getArtist(spotifyAlbum.artist.id)
.flatMap spotifyArtist ->
// Here I don't have the album and I can't to asign the image
【问题讨论】:
【参考方案1】:并行解决方案
要结合多个数据源,最好的运算符是zip:
Single.zip(getAlbum(albumId), getArtist(artistId),
BiFunction<SpotifyAlbumDTO, SpotifyArtistDTO, SpotifyAlbumDTO> album, artist ->
val artistImage = artist.imageUrl
album.artist.image = artistImage
album //return value of the merged observable
).subscribe album: SpotifyAlbumDTO?, error: Throwable? ->
emitter.onNext(album.toAlbum())
它将并行运行所有的可观察对象,并在每个可观察对象完成后执行合并功能。
如果你有更多的 observable 要 zip,你可以使用 Function3、Function4、...
顺序解决方案(编辑)
如果由于需要顺序执行请求而无法并行执行,则可以使用 flatmap 函数的resultSelector。它采用 flatMap 之前的项目和 flatmap 之后的分组集合。这样您就可以轻松创建模型组,而不会混淆 Pair
唯一的问题是:Single
不支持这种平面图。
您可以通过将返回类型从 Single
更改为 Observable
或在运行时使用 toObservable
运算符转换您的 Single
来解决此问题。
getAlbum(albumId)
.toObservable()
.flatMap(album: SpotifyAlbumDTO -> getArtist(album.artist.id).toObservable(),
album:SpotifyAlbumDTO, artist:SpotifyArtistDTO ->
album.artist.image = artist.imageUrl
album
)
?.subscribe album: SpotifyAlbumDTO ->
print(album)
【讨论】:
抱歉,我不能使用 zip,因为在执行 getAlbum() 之前我不知道艺术家 ID 我误解了你的问题,我已经更新了我的答案 谢谢!这就是我需要的【参考方案2】:您可以使用Pair
和flatMap
将您的结果包装在一起:
_spotifyService.getAlbum(albumId).flatMap spotifyAlbum ->
_spotifyService.getArtist(spotifyAlbum.artist.id)
.flatMap artist ->
Single.just(spotifyAlbum, artist)
.subscribe pair: Pair<Album, Artist> ->
// grab results
val album = pair.first
val artist = pair.second
【讨论】:
谢谢,这是一个很棒的方法!我想知道其他解决方案,我认为必须存在一个运算符来积累以前的结果,因为如果你想连接更多的电话,我认为这不是最好的。这不是一个奇怪的案例,必须是更好的解决方案!以上是关于RXJava/Kotlin - 链接单个结果为一个的主要内容,如果未能解决你的问题,请参考以下文章
RxJava/Kotlin Observable 方法调用链 - 如何终止?
kotlin 中的 Observable.combineLatest 类型推断