Slide 1

Slide 1 text

Introduction to Kotlin Coroutines KugBel & GDGBrussels February 2019

Slide 2

Slide 2 text

Async is hard!

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Solution 2: async / await async(UI) { val image = loadImageAsync(url).await() setImage(image) }

Slide 5

Slide 5 text

What is a Coroutine?

Slide 6

Slide 6 text

Coroutines are like lightweight threads Coroutine is a sequence of instructions Multiple coroutines can be executed concurrently Share resources such as memory

Slide 7

Slide 7 text

Computation that can be suspended Thread is not blocked!

Slide 8

Slide 8 text

Key Concepts Coroutine Builders Suspending functions Coroutine Scope Coroutine Dispatchers

Slide 9

Slide 9 text

Coroutine Builders launch - fire and forget async - returns a Deferred

Slide 10

Slide 10 text

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!

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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 }

Slide 13

Slide 13 text

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!

Slide 14

Slide 14 text

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 }

Slide 15

Slide 15 text

Composing suspending functions fun main() = runBlocking { 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

Slide 16

Slide 16 text

Composing suspending functions fun main() = runBlocking { 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

Slide 17

Slide 17 text

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.

Slide 18

Slide 18 text

Composing suspending functions fun main() = runBlocking { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") }

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Coroutine Dispatchers fun main() = runBlocking { 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}") } }

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

How can I use them?

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

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