Alot of android programmers are now approaching Kotlin, a programming language based on Java and the JVM that is being used for developing Android applications. Similarly to what usually happens with Java-based Android apps, one of the main problems when approaching Android development in Kotlin is the management of asynchronous code. In Java, this has been solved by the AsyncTask class, or the runOnUiThread method. In Kotlin, we need something different.

During Codemotion Milan 2018, Fabio Collini, Google Developer Expert and Senior Android Developer, delivered a speech on how to implement asynchronous code in Kotlin. In particular, he described two different approaches: the first one using coroutines, the second based on a library named ReactiveX Java (or RxJava in short). Both these approaches allow us to implement and support asynchronous operations, and they can be also used together and interchangeably.
In this post we will provide a quick overview on how these approaches differ from each other.

A sample service

Fabio Collini started the discussion about using RxJava or coroutines by showing a sample interface for a service aimed at obtaining information from StackOverflow. Since such a service is made up of asynchronous methods, it is perfect for our purposes.
The first difference is, therefore, how can we define methods that are asynchronous? With RxJava, we need to use the Single class as type for the return value:

interface StackOverflowService {
	@GET("/users")
	fun getTopUsers(): Single<List<User>>
    
	@GET("/users/{userId}/badges")
	fun getBadges(
    		@Path("userId") userId: Int
	): Single<List<Badge>>
    
	@GET("/users/{userId}/top-tags")
	fun getTags(
   		@Path("userId") userId: Int
	): Single<List<Tag>>
}

 

This allows to use the subscribe method in order to wait for the response.
With coroutines, there are two possibilities: the first one is similar to the above, but uses the Deferred class:

interface StackOverflowService {
	@GET("/users")
	fun getTopUsers(): Deferred<List<User>>
    
	@GET("/users/{userId}/badges")
	fun getBadges(
    		@Path("userId") userId: Int
	): Deferred<List<Badge>>
    
	@GET("/users/{userId}/top-tags")
	fun getTags(
   		@Path("userId") userId: Int
	): Deferred<List<Tag>>
}

 

However, a recent upgrade of Kotlin allows us to declare suspending functions, which in practice makes the code appears like synchronous, even it is actually the opposite:

interface StackOverflowService {
	@GET("/users")
	suspend fun getTopUsers(): List<User>
    
	@GET("/users/{userId}/badges")
	suspend fun getBadges(
    		@Path("userId") userId: Int
	): List<Badge>
    
	@GET("/users/{userId}/top-tags")
	suspend fun getTags(
   		@Path("userId") userId: Int
	): List<Tag>
}

 

In the following, we will consider the latter approach, since this makes the code cleaner.

Using the service methods

Now, if we want to use the aforementioned service, RxJava and coroutines require different approaches.
As mentioned above, RxJava requires using the subscribe method:

class MyViewModel(
	private val service: StackOverflowService
) : ViewModel() {

	private val disposable = CompositeDisposable()

	fun load() {
		disposable +=
			service.getTopUsers()
				.subscribeOn(io())
				.observeOn(mainThread())
				.subscribe(
					{ users -> updateUi(users) },
					{ e -> updateUi(e) }
				)
	}
    
	private fun updateUi(s: Any) {
		//...
	}
    
	override fun onCleared() {
		disposable.clear()
	}
}

 

The subscribe method accepts two parameters: the first is the one we want to execute, while the second one (e -> updateUi(e)) is used in case of errors.

While RxJava is synchronous by default (and consequently we resorted to subscribe), using coroutines and suspending functions allows us to write code that is automatically interpreted as asynchronous, even if it appears as synchronous. To understand this difference, compare the following snippet with the previous one: they are equivalent in functionality.

class MyViewModel(
	private val service: StackOverflowService
) : ViewModel() {

	fun load() {
		viewModelScope.launch {
			try {
				val users = service.getTopUsers()
				updateUi(users)
			} catch (e: Exception) {
				updateUi(e)
			}
		}
	}
    
	private fun updateUi(s: Any) {
		//...
	}
}

 

Here, the viewModelScope simplifies the code, even if it is not available yet with Kotlin. However, an implementation is provided in this link.

In general, you can do even more complicated things by using coroutines or RxJava. Additional code examples by Fabio Collini are available on GitHub.

Coroutines or RxJava?

After this quick overview about coroutines and RxJava, one might ask which solution is the best one. In terms of methods count, RxJava is bigger than a solution based on coroutines only. However, this difference can be eliminated by using Proguard and its code optimization. The following graphs taken from Fabio Collini’s slides depict this.
 

 
So, which approach should we use in production code?
In order to answer such question, Fabio Collini proposed the following “algorithm”:

  • if you are already using RxJava and it works for you, then use RxJava
  • if the architecture is based on reactive stream, then use RxJava
  • if the project is multiplatform with Kotlin Native, then use coroutines
  • if the codebase is Java/Kotlin, then use RxJava
  • else, use coroutines

 
As an additional note, consider that coroutines are generally easier to understand, while the learning curve for RxJava is steeper. So in general coroutines are preferable, except for the aforementioned cases.

#Mobile ·