【问题标题】:RXJava/Kotlin - Chaining Single results in oneRXJava/Kotlin - 链接单个结果为一个
【发布时间】: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         
}

【问题讨论】:

    标签: rx-java system.reactive rx-kotlin


    【解决方案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】:

    您可以使用PairflatMap 将您的结果包装在一起:

    _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      
    }
    

    【讨论】:

    • 谢谢,这是一个很棒的方法!我想知道其他解决方案,我认为必须存在一个运算符来积累以前的结果,因为如果你想连接更多的电话,我认为这不是最好的。这不是一个奇怪的案例,必须是更好的解决方案!
    猜你喜欢
    • 2016-07-31
    • 2021-05-29
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多