I have three API calls in which two are dependent on each other.
I have setted the following endpoints:
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>
}
and
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>
}
My repository looks as follows:
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)
}
Right now in ViewModel I would like to fetch all needed data (three models). So I should have some method, in which I will be doing all three requests one after another, as follows:
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)
and after all that I need to create new model, which includes all fetched data. Something like:
val cityModel = CityModel(
locationModel,
weatherModel,
placesModel
)
Does anybody know how to do something like this using RxJava in Kotlin?
CodePudding user response:
I'm sure there are multiple ways to do this. The one that comes to mind is not super elegant. You can use flatMap, but you will need to keep track of your models along the way so you can build the last model. You can try using Pair.
Here's the whole idea:
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
)
}
}
So first you getCoordinates
and use the result to get the weather. Using to you create a Pair that gets "piped" into the next flatMap
.
Once inside the last flatMap
you destructure the pair into locationModel
and weatherModel
and use them to fetch the place id.
With everything now you can simply build your CityModel
.
CodePudding user response:
You can try the share() operator. Something like below:
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) { .. }