Introduction to Kotlin Coroutines

Introduction to Kotlin Coroutines

Brief introduction to Kotlin Coroutines, presented before a workshop of introduction to Coroutines

820df515de752bffa0ce2644a7927186?s=128

David González

February 27, 2019
Tweet

Transcript

  1. Introduction to Kotlin Coroutines KugBel & GDGBrussels February 2019

  2. Async is hard!

  3. Solution 1: Callbacks loadImageAsync().whenComplete { image -> runOnUiThread { setImage(image)

    } }
  4. Solution 2: async / await async(UI) { val image =

    loadImageAsync(url).await() setImage(image) }
  5. What is a Coroutine?

  6. Coroutines are like lightweight threads Coroutine is a sequence of

    instructions Multiple coroutines can be executed concurrently Share resources such as memory
  7. Computation that can be suspended Thread is not blocked!

  8. Key Concepts Coroutine Builders Suspending functions Coroutine Scope Coroutine Dispatchers

  9. Coroutine Builders launch - fire and forget async - returns

    a Deferred<T>
  10. Our first coroutine fun main() { GlobalScope.launch { // launch

    new coroutine in background and continue delay(1000L) // non-blocking delay for 1 second (default time unit is ms) println("World!") // print after delay } println("Hello,") // main thread continues while coroutine is delayed } Hello, World!
  11. Suspending function A function that can suspend the execution of

    a coroutine It can be started, paused and resumed at a later time Can only be called within a coroutine or from another suspending function
  12. Our first coroutine fun main() { GlobalScope.launch { // launch

    new coroutine in background and continue delay(1000L) // non-blocking delay for 1 second (default time unit is ms) println("World!") // print after delay } println("Hello,") // main thread continues while coroutine is delayed }
  13. Our first suspending function fun main() { launch { doWorld()

    } println("Hello,") } // this is your first suspending function suspend fun doWorld() { delay(1000L) println("World!") } Hello, World!
  14. Composing suspending functions suspend fun doSomethingUsefulOne(): Int { delay(1000L) //

    pretend we are doing something useful here return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // pretend we are doing something useful here, too return 29 }
  15. Composing suspending functions fun main() = runBlocking<Unit> { val time

    = measureTimeMillis { val one = doSomethingUsefulOne() val two = doSomethingUsefulTwo() println("The answer is ${one + two}") } println("Completed in $time ms") } The answer is 42 Completed in 2017 ms
  16. Composing suspending functions fun main() = runBlocking<Unit> { val time

    = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") } The answer is 42 Completed in 1017 ms
  17. Coroutine Scope Defines a scope for new coroutines A scope

    controls the lifetime of coroutines through its job Every coroutine builder is an extension on CoroutineScope and inherits its coroutineContext to automatically propagate both context elements and cancellation.
  18. Composing suspending functions fun main() = runBlocking<Unit> { val time

    = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") }
  19. Composing suspending functions suspend fun concurrentSum(): Int = coroutineScope {

    val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } one.await() + two.await() } fun main() = runBlocking<Unit> { val time = measureTimeMillis { println("The answer is ${concurrentSum()}") } println("Completed in $time ms") } The answer is 42 Completed in 1017 ms
  20. Coroutine Dispatchers Determines the thread a coroutine runs on It

    can confine a coroutine to a specific thread, a threadpool or let it run unconfined
  21. Coroutine Dispatchers fun main() = runBlocking<Unit> { launch(Dispatchers.Main) { //

    context of the parent, main runBlocking coroutine println("main runBlocking : I'm working in thread ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { // not confined -- will work with main thread println("Unconfined : I'm working in thread ${Thread.currentThread().name}") } launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher println("Default : I'm working in thread ${Thread.currentThread().name}") } launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}") } }
  22. Coroutine Dispatchers main runBlocking : I 'm working in thread

    main Unconfined : I' m working in thread main Default : I 'm working in thread DefaultDispatcher-worker-1 newSingleThreadContext: I' m working in thread MyOwnThread
  23. How can I use them?

  24. None
  25. Let’s get to work https://codelabs.developers.google.com/codelabs/kotlin-coroutines $ git clone https://github.com/googlecodelabs/kotlin-coroutines.git