How to get two different types onto the same stream?


Let’s say that you have two rest calls. One call that takes a user id and returns a profile. And another that again takes a user id but this time returns a list of favorites.

The function calls might respectively look like the following:

fun getProfile(id: UUID): Single<Profile>

fun getFavorites(id: UUID): Single<Favorites>

Let’s say that Profile looks like the following:

data class Profile(val id: UUID, val email: String, val firstName: String, val lastName: String)

And that Favorites looks like the following:

data class Favorites(val id: UUID, val favorites: List<Song>)

The issue is that the types the return aren’t the same. So how would we merge these two items into one?

One way is with zip. The zip operator marble diagram looks like the following:

There are two different streams of different types that become one type at the end. Here is what zip looks like:

public static <T1, T2, R> Single<R> zip(
       SingleSource<? extends T1> source1, SingleSource<? extends T2> source2,
       BiFunction<? super T1, ? super T2, ? extends R> zipper
)

This might look intimidating at first glance, but breaking it down it has three different parts. It takes two different single sources this will be our observable for profile and favorites. And a third parameter which is a Bifunction that will be provided the each item emitted by the first two arguments and return a single item.

Since we need a container object to hold both values we can define an extended profile class that takes profile and favorites:

data class ExtendedProfile(val profile: Profile, val favorites: Favorites)

Using Zip we end up with something like this:

Single.zip<Profile, Favorites, ExtendedProfile>(getProfile(uuid), getFavorites(uuid), BiFunction { profile, favorites ->
   ExtendedProfile(profile, favorites)
})

And of course if we print it out we can see both profile and favorites are there.

ExtendedProfile(profile=Profile(id=9e79541d-7b1c-48d5-b8a1-667177f4c63b, email=john@random.com, firstName=John, lastName=Doe), favorites=Favorites(id=9826ed13-ad5a-4e1c-9dfb-61c22ecfe47c, favorites=[Song(id=6e7ab44f-7dbf-4a28-8b8c-046a931dd3a1, title=Werld is mine, album=You're a man now, boy, author=Raleigh Ritchie)]))

Awesome! We used the zip operator to combine two different object types into one.

BEFORE YOU GO
Get this FREE guide to RxJava with a bonus chapter that will help you avoid RxJava beginner mistakes.

I'll show you the exact mistakes and solutions so that you can jumpstart your Rx Development such as:

  • Avoiding bugs due to concurrency configuration
  • Avoiding bugs with multiple subscriptions
  • Avoiding bugs due to error handling mistakes


I'll even throw in the full guide as a PDF

Comments 1

  1. Nice. Definitely could have used that in an Android app I made last year. I was using a few AWS services with AsyncTask. I had multiple requests going on at the same time: one to see if the session had expired, one to get the content for the main RecyclerView, and another to fetch profile/other data. I learned a lot from the experience. Thanks for the RxJava course!

Leave a Reply

Your email address will not be published. Required fields are marked *