A quick look at Async-Await in Android

Original author: Niek Haarman
  • Transfer
From translator

This is my first translation, so I apologize for the inaccuracies. If you find translation errors, please report it. I have not found a better translation of the word soroutine than coroutine , so I decided to use the original. If you have any ideas about this, I will be glad to know.


Kotlin version 1.1 will bring coroutin'y to the language , which allow you to pause the calculation at some point, and then continue later. An obvious example of this feature is async-await , which was added to C # several years ago.


Every android developer knows that when we deal with network requests or other I / O tasks, we need to make sure that the main thread is not blocked, and that we do not touch the UI from the background thread. Over the years, dozens of receptions have come and gone. This article lists the most popular and shows examples of the convenience that async-await brings with it.


Scenario


We want to get the Github user data and put it in the database, and then show the result on the screen. I did not explain the approaches, they will say everything for themselves.


Good old Thread


Manual control, 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 AsyncTask


Nobody uses them anymore, right?


fun asyncTask() {
  object : AsyncTask() {
    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


And who uses Callback-hell?


fun callbacks() {
  githubApi.userFromCall().enqueue(object : Callback {
    override fun onResponse(call: Call, response: Response) {
      val user = response.body()
      userRepository.storeCallback(user) {
        callbacksTV.text = "callbacks: [$user]"
      }
    }
    override fun onFailure(call: Call, t: Throwable) {
      if (t is IOException)
        callbacksTV.text = "callbacks: [User retrieval failed.]"
      else
        throw t
    }
  })
}

Rx


Provides cool 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


How do you look at this?


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.]"
  }
}

Here, the asyncUI (and a similar async <T> ) method will include coroutin's functionality, which provides access to the await method . Each time execution reaches the await method , calculations are paused until the parameter is evaluated, but the thread in which the call is made is not blocked. After that, coroutine will continue to execute. The asyncUI method ensures that execution continues in the main thread.




As you noticed, coroutine improves code readability. They are available now in kotlin version 1.1-M02. The latest async-await example uses a library that I wrote for the possibility of using coroutines on Android. If you want to know more about coroutins, you can check out the informal description.


PS: This article does not contain cancellation of executions and deletion of listeners, which may contain links to activi. Each approach may have a similar option, but without leaks.


In the next article I did a more detailed analysis of async-await.


Also popular now: