Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Better Async With Kotlin Coroutines

Better Async With Kotlin Coroutines

Better Async With Kotlin Coroutines @ Kotlin Night Torino 2018

Leonardo Pirro

June 08, 2018
Tweet

More Decks by Leonardo Pirro

Other Decks in Programming

Transcript

  1. Why Coroutines? Coroutines simplify asynchronous programming by providing a set

    of APIs to write code in direct style (sequentially)
  2. Why Coroutines? • Asynchronous programming is becoming really important for

    developers • The other tools that we have today introduced a lot of complexity • Callback Hell
  3. What we have now Thread { code } .start() object

    MyAsyncTask: AsyncTask() { override fun doInBackground { code } override fun onPostExcecute { code } } Observable.just(1,2,3,4) .map { code } .doOnEach { code } .doOnError { code } .subscribeOn( { onNext }, { onError } )
  4. What we have now Thread { code } .start() object

    MyAsyncTask: AsyncTask() { override fun doInBackground { code } override fun onPostExcecute { code } } Observable.just(1,2,3,4) .map { code } .doOnEach { code } .doOnError { code } .subscribeOn( { onNext }, { onError } )
  5. What we have now WANT fun loadNews() = launch {

    view.showLoading() val result = async { // computation }.await() view.hideLoading() view.showData(result) }
  6. Coroutines • Introduced in Kotlin 1.1 • Experimental (but several

    companies, including us in IQUII, are using them in production with zero problems)
  7. coroutine builder coroutine context suspend function builders to launch coroutine

    coroutine dispatchers mark suspention point Coroutines
  8. coroutine builder builders to launch coroutine coroutine context suspend function

    coroutine dispatchers mark suspention point Coroutines
  9. coroutine builder coroutine context suspend function builders to launch coroutine

    coroutine dispatchers mark suspention point Coroutines
  10. coroutine builder coroutine context suspend function builders to launch coroutine

    coroutine dispatchers mark suspention point Coroutines
  11. Coroutines - Builders withContext return result uncaught exception crashes your

    app T launch Job fire and forget uncaught exception crashes your app async Deferred returns non-blocking future uncaught exception is shared inside the resulting Deferred
  12. Coroutines - Context coroutine context UI dispatch execution into Android

    main thread CommonPool dispatch execution into background thread Unconfined dispatch execution into current thread
  13. Coroutines - Suspend Function suspend fun fetchNews(): News suspend function

    fun fetchNews(listener: Continuation<News>) Trasformed to
  14. How to create a coroutine fun loadPlayes() { view?.showLoading() val

    result = dataManager.getPlayers() view?.showPlayers(result) view?.hideLoading() }§
  15. How to create a coroutine fun loadPlayes() = launch( §

    UI § ) { view?.showLoading() val result = dataManager.getPlayers() view?.showPlayers(result) view?.hideLoading() }§
  16. How to create a coroutine Parent coroutine fun loadPlayes() =

    launch( § UI § ) { § view?.showLoading() val result = dataManager.getPlayers() view?.showPlayers(result) view?.hideLoading() }§
  17. How to create a coroutine Result in UI Thread fun

    loadPlayes() = launch(UI) { § view?.showLoading() val result = dataManager.getPlayers() view?.showPlayers(result) view?.hideLoading() }§
  18. How to create a coroutine fun loadPlayes() = launch(UI) {

    view?.showLoading() val result = dataManager.getPlayers() view?.showPlayers(result) view?.hideLoading() }§
  19. How to create a coroutine fun loadPlayes() = launch(UI) {

    view?.showLoading() val result = withContext(CommonPool) { dataManager.getPlayers() } view?.showPlayers(result) view?.hideLoading() }§
  20. How to create a coroutine fun loadPlayes() = launch(UI) {

    view?.showLoading() val result = withContext(CommonPool) { dataManager.getPlayers() } view?.showPlayers(result) view?.hideLoading() }§ child coroutine
  21. How to create a coroutine fun loadPlayes() = launch(UI) {

    view?.showLoading() val result = withContext(CommonPool) { dataManager.getPlayers() } view?.showPlayers(result) view?.hideLoading() }§
  22. Cancelling a coroutine var job: Job? = null fun onPlayerButtonClicked(){

    job = loadPlayers() } fun onBackClicked(){ job?.cancel() } private fun loadPlayers() = launch(UI) { // code }
  23. Cancelling a coroutine var job: Job? = null fun onPlayerButtonClicked(){

    job = loadPlayers() } fun onBackClicked(){ job?.cancel() } private fun loadPlayers() = launch(UI) { // code }
  24. Cancelling a coroutine var job: Job? = null fun onPlayerButtonClicked(){

    job = loadPlayers() } fun onBackClicked(){ job?.cancel() } private fun loadPlayers() = launch(UI) { // code }
  25. Error handling - try/catch block fun loadPlayes() = launch(UI) {

    view?.showLoading() try { val result = withContext(CommonPool) { dataManager.getPlayers() view?.showPlayers(result) } catch (e: IllegalArgumentException) { // handle errors } view?.hideLoading() }
  26. Error handling - Store inside Deferred fun loadPlayes() = async(UI)

    { view?.showLoading() val task = async(CommonPool) { dataManager.getPlayers() } val result = task.await() view?.showPlayers(result) view?.hideLoading() }
  27. Error handling - Store inside Deferred var job: Deferred<*> =

    loadPlayes() job.invokeOnCompletion { it?.printStackTrace() }
  28. Other cool stuff - Retrofit 2 Adapter interface MyApiService {

    @GET("user") fun getuser(): Deferred<User> // or... @GET("user") fun getuser(): Deferred<Response<User>> }
  29. Link utili • Kotlin community: https://kotlinlang.org/community • Official Slack: http://slack.kotlinlang.org

    • Android Developers Italy: https://androiddevsitaly.slack.com • Kotlin Coroutines official guide: https://github.com/Kotlin/ kotlinx.coroutines/blob/master/coroutines-guide.md Slide of this talk: https://speakerdeck.com/lpirro