j2emanue j2emanue - 2 months ago 19
Android Question

retrofit2 and rxjava - how to combine two dependent network calls in android

I am having some trouble understanding how i can chain two network calls together. I am using retrofit2 and rxJava. i am using the Yelp API and already have a gson Pojo for the businesses i want to capture. But the api call for business does not include the reviews so after i get the business i have to make another network call to get the review (based on the business id from the first call).

so what i want to happen is the following:
1. make a api call to get the business ID (given a search term user supplied).
2. after one completes i need to use the business ID to get the review.

Both are different api calls.

one call to get the business ID looks like this:

https://api.yelp.com/v3/businesses/search?term=delis&latitude=37.786882&longitude=-122.399972


and the other call to get the reviews is like this:

https://api.yelp.com/v3/businesses/molinari-delicatessen-san-francisco/reviews


So the second calls depends on data from the first call.

in retrofit2 i have the following set up as services:

@GET("v3/businesses/search")
Observable<Businesses> getBusinessesRx(
@Query("term") String term,
@Query("latitude") String latitude,
@Query("longitude") String longitude);

@GET("v3/businesses/{id}/reviews")
Observable<Businesses> getReviewsRx(
@Path("id") String businessID);


but notice i am using a Businesses pojo in both. Not sure if i can do that. The Businesses gson pojo is for the first call (in # 1) to get group of businesses given a search term. But i wouldnt' mind if i can just put in a extra field for the reviews and some how populate that. This way my businesses class can have reviews for every business found.

I am not sure how to start this in RXjava. i know i need a flatmap but im a little confused about the POJOs to use and how to make it work. this is on a android device.

my businesses pojo looks like this if needed:

public class Businesses {

@SerializedName("businesses")
@Expose
private List<Business> businesses = new ArrayList<Business>();
@SerializedName("total")
@Expose
private Integer total;

/**
*
* @return
* The businesses
*/
public List<Business> getBusinesses() {
return businesses;
}

/**
*
* @param businesses
* The businesses
*/
public void setBusinesses(List<Business> businesses) {
this.businesses = businesses;
}

/**
*
* @return
* The total
*/
public Integer getTotal() {
return total;
}

/**
*
* @param total
* The total
*/
public void setTotal(Integer total) {
this.total = total;
}


}

and my business pojo (for each individual business) looks like this:

public class Business {

@SerializedName("image_url")
@Expose
private String imageUrl;
@SerializedName("id")
@Expose
private String id;
@SerializedName("name")
@Expose
private String name;
@SerializedName("location")
@Expose
private Location location;
@SerializedName("rating")
@Expose
private Integer rating;
@SerializedName("price")
@Expose
private String price;
@SerializedName("categories")
@Expose
private List<Category> categories = new ArrayList<Category>();
@SerializedName("phone")
@Expose
private String phone;
@SerializedName("review_count")
@Expose
private Integer reviewCount;
@SerializedName("coordinates")
@Expose
private Coordinates coordinates;
@SerializedName("url")
@Expose
private String url;

/**
*
* @return
* The imageUrl
*/
public String getImageUrl() {
return imageUrl;
}

/**
*
* @param imageUrl
* The image_url
*/
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

/**
*
* @return
* The id
*/
public String getId() {
return id;
}

/**
*
* @param id
* The id
*/
public void setId(String id) {
this.id = id;
}

/**
*
* @return
* The name
*/
public String getName() {
return name;
}

/**
*
* @param name
* The name
*/
public void setName(String name) {
this.name = name;
}

/**
*
* @return
* The location
*/
public Location getLocation() {
return location;
}

/**
*
* @param location
* The location
*/
public void setLocation(Location location) {
this.location = location;
}

/**
*
* @return
* The rating
*/
public Integer getRating() {
return rating;
}

/**
*
* @param rating
* The rating
*/
public void setRating(Integer rating) {
this.rating = rating;
}

/**
*
* @return
* The price
*/
public String getPrice() {
return price;
}

/**
*
* @param price
* The price
*/
public void setPrice(String price) {
this.price = price;
}

/**
*
* @return
* The categories
*/
public List<Category> getCategories() {
return categories;
}

/**
*
* @param categories
* The categories
*/
public void setCategories(List<Category> categories) {
this.categories = categories;
}

/**
*
* @return
* The phone
*/
public String getPhone() {
return phone;
}

/**
*
* @param phone
* The phone
*/
public void setPhone(String phone) {
this.phone = phone;
}

/**
*
* @return
* The reviewCount
*/
public Integer getReviewCount() {
return reviewCount;
}

/**
*
* @param reviewCount
* The review_count
*/
public void setReviewCount(Integer reviewCount) {
this.reviewCount = reviewCount;
}

/**
*
* @return
* The coordinates
*/
public Coordinates getCoordinates() {
return coordinates;
}

/**
*
* @param coordinates
* The coordinates
*/
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}

/**
*
* @return
* The url
*/
public String getUrl() {
return url;
}

/**
*
* @param url
* The url
*/
public void setUrl(String url) {
this.url = url;
}


}

Answer

I'm not sure if I understand correctly but from first call you receive list of Business and than for each of those Business you need to get review. If so, than you can use following code:

ApiService service = Retrofit.create(ApiService.class);
service.getBusinessesRx("delis", "37.786882", "-122.399972")
        .map(Businesses::getBusinesses)
        .flatMap(Observable::from)
        .map(Business::getId)
        .flatMap(service::getReviewsRx)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(businesses -> updateUi());