This is my first translation, so I apologize for the inaccuracies. If you find errors in the translation, please report it. I did not find a better translation of the word coroutine than coroutine , so I decided to use the original. If you have ideas about this, I will be glad to know.
Kotlin version 1.1 will bring into the language coroutins , which allow you to suspend the calculations at some point, and then continue them 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 does not lock, and also that we don’t touch the UI from the background thread. Over the years, dozens of tricks have come and gone. This article lists the most popular, and shows examples of the convenience that async-await carries with it.
We want to get user data from Github and put it in the database, and then show the result on the screen. I did not explain the approaches, they will say it all for themselves.
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() }
Nobody uses them 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() }
Does anyone use Callback-hell?
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 } }) }
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 } ) }
And how do you look at it?
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 the similar async <T> ) method includes the functionality of coroutins, which provides access to the await method. Each time the execution reaches the await method, the calculations are suspended until the parameter is calculated, but the thread on which the call occurred is not blocked. After this, coroutine will continue its execution. The asyncUI method ensures that execution continues in the main thread.
As you notice, coroutine improves the readability of the code. They are available now in version kotlin 1.1-M02. The last example async-await uses the library I wrote to enable the use of coroutines on Android. If you want to learn more about coroutins, you can read an informal description.
PS: This article does not contain cancellation of executions and deletion of listeners that may contain links to activations. Each approach may have a similar option, but without leaks.
In the following article, I made a more detailed analysis of async-await.
Source: https://habr.com/ru/post/314574/
All Articles