RxJava 中相互依赖的多个 Retrofit 请求

Posted

技术标签:

【中文标题】RxJava 中相互依赖的多个 Retrofit 请求【英文标题】:Multiple Retrofit requests dependent on each other in RxJava 【发布时间】:2021-11-25 19:12:48 【问题描述】:

我有三个 API 调用,其中两个相互依赖。

我设置了以下端点:

interface WeatherApi 

    @GET("/data/2.5/onecall")
    fun getWeather(
        @Query("lat") lat: Double,
        @Query("lon") lon: Double,
        @Query("exclude") exclude: String,
        @Query("units") units: String,
        @Query("appid") appKey: String
    ): Observable<WeatherModel>

    @GET("/geo/1.0/direct")
    fun getCoordinates(
        @Query("q") cityName: String,
        @Query("appid") appKey: String
    ): Observable<LocationModel>

    @GET("geo/1.0/reverse")
    fun getNameForLocation(
        @Query("lat") lat: Double,
        @Query("lon") lon: Double,
        @Query("appid") appKey: String
    ): Observable<LocationModel>


interface PlacesApi 

    @GET("/maps/api/place/findplacefromtext/json")
    fun getPlaceId(
        @Query("input") cityName: String,
        @Query("inputtype") inputType: String,
        @Query("fields") fields: String,
        @Query("key") appKey: String
    ): Observable<PlacesModel>


我的存储库如下所示:

class WeatherRepository constructor(
    private val weatherService: WeatherApi,
    private val placesService: PlacesApi,
) 

    fun getCoordinates(cityName: String, appKey: String) =
        weatherService.getCoordinates(cityName, appKey)

    fun getWeather(lat: Double, lon: Double, exclude: String, units: String, appKey: String) =
        weatherService.getWeather(lat, lon, exclude, units, appKey)

    fun getPlaceId(placeName: String, appKey:String) =
        placesService.getPlaceId(placeName, "textquery", "photos", appKey)


现在我想在 ViewModel 中获取所有需要的数据(三个模型)。所以我应该有一些方法,其中我将依次执行所有三个请求,如下所示:

locationModel = weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY)
weatherModel = weatherRepository.getWeather(locationModel[0].lat!!, locationModel[0].lon!!)
placesModel = weatherRepository.getPlaceId(weatherModel, BuildConfig.PLACES_API_KEY)

毕竟我需要创建新模型,其中包括所有获取的数据。比如:

val cityModel = CityModel(
    locationModel,
    weatherModel,
    placesModel
)

有人知道如何在 Kotlin 中使用 RxJava 来做这样的事情吗?

【问题讨论】:

zipWith 想到了***.com/questions/30219877/… 【参考方案1】:

我确信有多种方法可以做到这一点。想到的不是超级优雅。您可以使用flatMap,但您需要在此过程中跟踪您的模型,以便构建最后一个模型。您可以尝试使用Pair。

这是整个想法:

 weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY)
     .flatMap  locationModel ->
       weatherRepository.getWeather(locationModel[0].lat!!, locationModel[0].lon!!)
         .map  locationModel to it 
     
     .flatMap  (locationModel, weatherModel) ->
        weatherRepository.getPlaceId(weatherModel, BuildConfig.PLACES_API_KEY)
          .map 
            CityModel(
              locationModel,
              weatherModel,
              it
            )
          
     

所以首先你 getCoordinates 并使用结果来获取天气。使用to,您可以创建一个“管道”到下一个flatMap 的Pair。

一旦进入最后一个flatMap,您就可以将这对分解为locationModelweatherModel,并使用它们来获取地点ID。

现在您可以轻松构建您的CityModel

【讨论】:

我会使用switchMap,但我认为这些真的是Single 而不是Observable 所以是的,flatMap 也可以。 鉴于他们是改造电话,我认为源 observable 不会改变。我不明白为什么 switchMap 在这种特殊情况下会有不同的表现。 如果你假设 Observable 只发射一次,那么它的行为不会有什么不同,但如果它发射不止一次,它就会有不同。正如我在之前的评论中所说,如果只有一个发射,它们应该是 Single 我明白了。我不知道从 Retrofit 返回的 observable 会发出多个元素。也许这是可能的,我只是从来没有遇到过。我正是这个意思。在这种情况下,switchMap 不会给出与flatMap 不同的行为。确实,如果是这样的话,他们应该是Singles【参考方案2】:

你可以试试 share() 操作符。如下所示:

locationModelObservable = weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY).share()
weatherModelObservable = locationModel.flatMap  weatherRepository.getWeather(it[0].lat!!, it[0].lon!!) .share()
placesModelObservable = weatherModel.flatMap  weatherRepository.getPlaceId(it, BuildConfig.PLACES_API_KEY) 

zip(locationModelObservable, weatherModelObservable, placesModelObservable)  .. 

【讨论】:

以上是关于RxJava 中相互依赖的多个 Retrofit 请求的主要内容,如果未能解决你的问题,请参考以下文章

带你走通 OkHttp+Retrofit+Rxjava

链接多个调用 RxJava、Room 和 Retrofit

RxJava和Retrofit的简单使用

Android - 框架之Retrofit+RxJava的使用

RxJava+Retrofit实现网络请求

RxJava + Retrofit