Note: this article was written for a preview version of coroutines for Kotlin. Its details have changed since then.

Kotlin 1.1 will bring coroutines to the language, which allows computations to be suspended at some points and continue later on. The obvious example is async-await, as introduced a couple of years ago in C#.

Every Android developer knows that when you deal with network requests and other I/O tasks, you will need to make sure you don’t block the main thread, and don’t touch the UI from a background thread.

Over the years dozens of techniques have come and gone. This article lists a few of the most used ones, and shows an example of the goodness that async-await can bring.

The scenario

We will fetch a user instance from the Github api and store it in some database. When this is done we show the result on-screen.

I won’t be explaining the techniques, as they should speak for themselves.

Plain old threads

Manual, full control

fun threads() {

val handler = Handler()



Thread {

try {

val user = githubApi.user()

userRepository.store(user)

handler.post {

threadsTV.text = "threads: [$user]"

}

} catch(e: IOException) {

handler.post {

threadsTV.text = "threads: [User retrieval failed.]"

}

}

}.start()

}

Android’s AsyncTask

Nobody uses these anymore, right?

fun asyncTask() {

object : AsyncTask<Unit, Unit, GithubUser?>() {



private var exception: IOException? = null



override fun doInBackground(vararg params: Unit): GithubUser? {

try {

val user = githubApi.user()

userRepository.store(user)

return user

} catch(e: IOException) {

exception = e

return null

}

}



override fun onPostExecute(user: GithubUser?) {

if (user != null) {

asyncTaskTV.text = "asyncTask: [$user]"

} else {

asyncTaskTV.text = "asyncTask: [User retrieval failed.]"

}

}

}.execute()

}

Callbacks

Callback-hell, anyone?

fun callbacks() {

githubApi.userFromCall().enqueue(object : Callback<GithubUser> {



override fun onResponse(call: Call<GithubUser>, response: Response<GithubUser>) {

val user = response.body()

userRepository.storeCallback(user) {

callbacksTV.text = "callbacks: [$user]"

}

}



override fun onFailure(call: Call<GithubUser>, t: Throwable) {

if (t is IOException)

callbacksTV.text = "callbacks: [User retrieval failed.]"

else

throw t

}

})

}

Rx

Getting to the good stuff..

fun rx() {

githubApi.userRx()

.flatMap { user ->

userRepository.storeRx(user).toSingle { user }

}

.observeOn(AndroidSchedulers.mainThread())

.subscribe(

{ user ->

rxTV.text = "rx: [$user]"

},

{ throwable ->

if (throwable is IOException)

rxTV.text = "rx: [User retrieval failed.]"

else

throw throwable

}

)

}

Async-Await

Now would you look at that?

fun asyncAwait() = asyncUI {

try {

val user = await(githubApi.userAsync())

await(userRepository.storeAsync(user))

asyncAwaitTV.text = "asyncAwait: [$user]"

} catch(e: IOException) {

asyncAwaitTV.text = "asyncAwait: [User retrieval failed.]"

}

}