Skip to content

Instantly share code, notes, and snippets.

@Evin1-
Created August 6, 2020 13:03
Show Gist options
  • Save Evin1-/847299ff79f9f5268cbfe57668c854bb to your computer and use it in GitHub Desktop.
Save Evin1-/847299ff79f9f5268cbfe57668c854bb to your computer and use it in GitHub Desktop.
Loop Cupcakes. Doing 2 network calls using RxJava Zip operator
<uses-permission android:name="android.permission.INTERNET" />
android {
//..
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
//.. https://square.github.io/retrofit/
//.. https://github.com/ReactiveX/RxAndroid
//.. https://github.com/akarnokd/RxJavaRetrofitAdapter
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.5'
implementation "com.github.akarnokd:rxjava3-retrofit-adapter:3.0.0"
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* Creates an instance of the UserService using a simple Retrofit builder using Moshi
* as a JSON converter and an RxJava adapter, this will append the endpoints set on
* the UserService interface (for example '/api', '/api?results=2') with the base URL
* set here, resulting on the full URL that will be called: 'https://randomuser.me/api' */
val service = Retrofit.Builder()
.baseUrl("https://randomuser.me/")
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create(UserService::class.java)
/* The RxJava Single that will call the user info endpoint */
val userInfoSingle = service.getUserInfo().map { it.results.first() }
/* The RxJava Single that will call the followers endpoint endpoint */
val followersSingle = service.getFollowers(10).map { it.results }
/* RxJava chain that calls the 2 endpoints in parallel, their results are going to be
* merged after they are both done using the UserZipper object, both calls will be made
* on a worker thread and then come back to the main thread using the subscribeOn and
* observeOn combination in the chain. If any of the calls fail, the whole RxJava chain
* will fail using the onError callback. The logging of either the error or completion
* of the operation is run on the main thread. */
Single.zip(userInfoSingle, followersSingle, UserZipper)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ Log.d("TAG_ ", it) }) { Log.e("TAG_ ", "Error happened! $it") }
}
}
/* A simple zipper that will map the result of both network calls using a String
* concatenation. This is run on a worker thread. */
object UserZipper : BiFunction<User, List<User>, String> {
override fun apply(user: User, followers: List<User>): String {
val followersEmails = followers.map { it.email }
return "$user has followers: $followersEmails"
}
}
/* Kotlin data/model classes that map the JSON response, we could also add Moshi
* annotations to help the compiler with the mappings on a production app */
data class UserResponse(val results: List<User>)
data class User(val email: String, val phone: String)
/* Retrofit service that maps the different endpoints on the API, you'd create one
* method per endpoint, and use the @Path, @Query and other annotations to customize
* these at runtime. These are just simulations to get a single and a list of users. */
interface UserService {
@GET("/api")
fun getUserInfo(): Single<UserResponse>
@GET("/api")
fun getFollowers(@Query("results") results: Int): Single<UserResponse>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment