KOTLIN COROUTINES AND ANDROID
SITTING IN A TREE...
KAI KOENIG (@AGENTK)
HELLO
HELLO
My name is Kai!
Software Architect in the web and mobile (Android) space 

from New Zealand.
Stuff I enjoy: Android, Kotlin, CFML, compilers and parsers, aviation and flying
small aircraft, cats and chickens, Nintendo video games of all ages!
Twitter: @AgentK
AGENDA
AGENDA
▸ Kotlin in 5 minutes
▸ Why coroutines?
▸ Using coroutines in your Kotlin code
▸ Libraries and coroutines on Android
KOTLIN IN 5 MINUTES
https://www.flickr.com/photos/tschiae/8080742303/
HISTORY OF KOTLIN (I)
▸ Jetbrains wanted a more efficient JVM language when building products
▸ Looked at Scala, Groovy, etc. but came up with their own language spec
▸ First shown at the JVM Language Summit in 2011
▸ Got some traction in Android-land in 2014
▸ Modern language features (lambdas, HOF etc) but Java 6 byte code
▸ Low methods count (~7000)
▸ Strong focus on concision and an efficient, bloat-free language
KOTLIN IN 5 MINUTES
HISTORY OF KOTLIN (II)
▸ Since 1.0 release in early 2016:
▸ multiple maintenance releases
▸ now at 1.0.7
▸ 1.1 was released in Feb 2017,
▸ currently at 1.1.51 (previously 1.1.5-1)
KOTLIN IN 5 MINUTES
HISTORY OF KOTLIN (III)
▸ At Google IO 2017, Kotlin became a first-grade language for Android
▸ Development of 1.2 is underway
▸ Java 9 compatibility
▸ Multiplatform projects
▸ Huge improvements to StdLib, type inference, smart cast etc.
▸ Strong community, lots of interesting frameworks, awesome support from
Jetbrains
KOTLIN IN 5 MINUTES
KOTLIN IN 5 MINUTES
PROMINENT LANGUAGE FEATURES
▸ Immutability
▸ String templates
▸ Explicit null handling
▸ Properties and Fields
▸ Data classes
▸ Extension functions
▸ Syntactic sugar
▸ Type inference
▸ Lambdas
▸ Collection API
▸ Type-safe builders
▸ Java-Kotlin-Interop
THE 1.1 RELEASE
OVERVIEW
▸ JavaScript target is not experimental anymore (browser & NodeJS)
▸ Full Kotlin language support
▸ Large part of the stdlib is supported
▸ Coroutines (JVM-only, experimental)
▸ Lightweight concurrency mechanism
▸ Alternative to threads
▸ Tooling improvements & more language features
WHY COROUTINES?
https://www.flickr.com/photos/61299367@N05/9448165205
WHY COROUTINES?
MOTIVATION
▸ Asynchronous programming is becoming increasingly important
▸ Problem: the need to avoid blocking introduces a lot of complexity
▸ Threads are:
▸ expensive to manage and limited
▸ complex in applications with lots of mutable state
▸ usually even more complex to deal with in UI-driven applications
▸ Callback hell (very common in Javascript)
http://slides.com/michaelholroyd/asyncnodejs/#/
WHY COROUTINES?
HISTORY
▸ Coroutines were first mentioned and used in Simula 67
▸ detach & resume keywords to suspend and then later resume execution
▸ Pushed aside by industry trend towards multi-threading
▸ C# has async/await
▸ Go was one of the first modern languages re-introducing coroutines
WHY COROUTINES?
COROUTINES IN KOTLIN (I)
▸ Kotlin’s approach: Suspending functions
▸ Function/lambda that can be suspended and resumed
▸ No context-switching on the OS level
▸ Minimal integration into the core language and stdlib, most of functionality
provided by libraries
▸ Design allows for a variety of asynchronous API methodologies to be
implemented on top of Kotlin coroutines
▸ Supposed to feel like writing traditional code
WHY COROUTINES?
COROUTINES IN KOTLIN (II)
▸ Easiest way to think about a coroutine is a very light-weighted thread
▸ They can run in parallel
▸ Coroutines can wait for each other
▸ They can communicate with each other
▸ Very, very cheap to create (compared to threads)
▸ A thread can run a lot of coroutines
WHY COROUTINES?
COROUTINES IN KOTLIN (III)
▸ Multiple layers of libraries and integration points:
▸ Language support: suspending functions
▸ Low-level library in kotlinx.coroutines
▸ Mid-level library in kotlinx.coroutines
▸ High-level libraries (Anko etc.)
USING COROUTINES IN
YOUR KOTLIN CODE
https://www.flickr.com/photos/97114911@N05/14720054418
USING COROUTINES IN YOUR KOTLIN CODE
FUNDAMENTALS
▸ Use Kotlin 1.1.4 as a minimum, better 1.1.51
▸ Enable experimental feature in Gradle
kotlin {
experimental {
coroutines 'enable'
}
}
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.2'
USING COROUTINES IN YOUR KOTLIN CODE
“HELLO WORLD”
▸ launch {…} starts new coroutine on CommonPool thread pool
▸ delay() is a suspending function (not blocking a thread)
fun main(args: Array<String>) {
println("Start on main thread")
launch(CommonPool) {
delay(5000)
println("Hello from coroutine")
}
Thread.sleep(10000)
println("Stop on main thread")
}
USING COROUTINES IN YOUR KOTLIN CODE
“HELLO WORLD” IN BETTER
▸ Wait for the coroutines to finish - launch {…} returns a Job object
fun main(args: Array<String>) = runBlocking {
println("Start on main thread")
val job = launch(CommonPool) {
delay(5000)
println("Hello from coroutine")
}
job.join()
println("Stop on main thread")
}
USING COROUTINES IN YOUR KOTLIN CODE
THREADS VS COROUTINES
import java.util.concurrent.atomic.AtomicInteger
import kotlin.concurrent.thread
fun main(args: Array<String>) {
val c = AtomicInteger()
for (i in 1..1_000_000)
thread(start = true) {
c.addAndGet(i)
}
println(c.get())
}
import kotlinx.coroutines.experimental.*
import java.util.concurrent.atomic.AtomicInteger
fun main(args: Array<String>) {
val c = AtomicInteger()
for (i in 1..1_000_000)
launch(CommonPool) {
c.addAndGet(i)
}
// Temporary hack to allow the coroutines to finish
Thread.sleep(2000)
println(c.get())
}
USING COROUTINES IN YOUR KOTLIN CODE
THREADS VS COROUTINES
USING COROUTINES IN YOUR KOTLIN CODE
ASYNC/AWAIT (I)
▸ async {…} starts new coroutine and returns a Deferred<T> object
▸ Deferred<T>.await() returns result of the coroutine
▸ await() needs to be called from inside a coroutine, because it needs to suspend
in a non-blocking way
▸ Solution: wrap into runBlocking {…} coroutine
▸ Starts coroutine and wait until it’s finished
USING COROUTINES IN YOUR KOTLIN CODE
ASYNC/AWAIT (II)
import kotlinx.coroutines.experimental.*
fun main(args: Array<String>) {
val deferred = (1..1_000_000).map { n ->
async (CommonPool) {
n
}
}
runBlocking {
val sum = deferred.sumBy { it.await() }
println("Sum: $sum")
}
}
USING COROUTINES IN YOUR KOTLIN CODE
SUSPEND FUNCTIONS (I)
▸ Coroutines can suspend without blocking a thread
▸ Functions that might suspend need to be marked with the suspend keyword
▸ They can only be called from another suspend function or a coroutine
USING COROUTINES IN YOUR KOTLIN CODE
SUSPEND FUNCTIONS (II)
fun main(args: Array<String>) {
val deferred = (1..1_000_000).map { n ->
async (CommonPool) {
doWork(n)
}
}
runBlocking {
...
}
}
suspend fun doWork(n: Int) : Int {
delay(50)
return n
}
USING COROUTINES IN YOUR KOTLIN CODE
BEHIND THE SCENES
▸ Kotlin coroutines are very light on language features:
▸ suspend the only new keyword added to the language and acts pretty much
like a compiler flag
▸ Continuation and CoroutineContext in stdlib
▸ All the rest is in the kotlinx.coroutines library
This makes the design of Kotlin coroutines very composable.
USING COROUTINES IN YOUR KOTLIN CODE
MORE BEHIND THE SCENES
▸ At compilation:
▸ Suspending functions compile to functions with a general callback interface
of type Continuation
▸ Code with suspension points compiles to state machine
▸ launch, runBlocking, async etc. are often called coroutine builders
USING COROUTINES IN YOUR KOTLIN CODE
LAUNCH VS ASYNC
▸ Conceptually very similar
▸ launch {…} returns a Job, no resulting value
▸ async {…} returns a Deferred - a future that can be used to obtain a value
▸ async generally suited better in situations with independent concurrent flows
USING COROUTINES IN YOUR KOTLIN CODE
WAITING AND CANCELLING
▸ cancel() and then join() can be used to terminate a coroutine execution early
▸ Job has an extension function cancelAndJoin() doing both at once
val job = launch {
repeat(1000) { i ->
println("job: I'm sitting here and delaying $i ...")
delay(500L)
}
}
delay(1300L)
println("main: I'm really over waiting!")
job.cancel()
job.join() // or use: job.cancelAndJoin()
println("main: Let's go.")
USING COROUTINES IN YOUR KOTLIN CODE
DEALING WITH TIMEOUTS
▸ Quite often the motivation for cancelling is a timeout:
▸ Track yourself via the Job instance
▸ Use withTimeout() {…}
withTimeout(1300L) {
repeat(1000) { i ->
println("I'm waiting $i ...")
delay(500L)
}
}
USING COROUTINES IN YOUR KOTLIN CODE
THAT’S NOT ALL OF IT YET
▸ Coroutine context
▸ Coroutines and threads
▸ Channels
▸ Pipelines
▸ Dealing with state
▸ Shared (mutable) state & Actors
Compare Coroutines with Java Futures API
LIBRARIES AND
COROUTINES ON
ANDROID
https://www.flickr.com/photos/qiaomeng/4665885561/
MOTIVATION
▸ In general, UI-driven apps need to be aware of long-running processes
▸ In Android specifically, we can’t do any networking on the UI thread.
▸ The kotlinx.coroutines library by Jetbrains provides a starting point for
Android, too.
LIBRARIES AND COROUTINES ON ANDROID
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.19.2'
UI CONTEXT
▸ The Android library provides access to a coroutine context for the UI thread
▸ Coroutine launches in UI thread, UI updates and suspending functions are
possible
▸ Non-blocking, UI is not frozen
LIBRARIES AND COROUTINES ON ANDROID
launch(UI) {
for (i in 10 downTo 1) {
hello.text = "Countdown $i ..."
delay(500)
}
hello.text = "Done!"
}
OTHER UI THREAD CONCERNS
▸ For Jobs and cancelling coroutines, the same general principles still apply
▸ using launch {…} provides a reference to a Job
▸ can be cancelled with cancel() - for instance via UI control
▸ In UI scenarios useful to write own coroutines builders as extension functions
LIBRARIES AND COROUTINES ON ANDROID
button.onClick {
...
}
fun View.onClick(action: suspend () -> Unit) {
setOnClickListener {
launch(UI) {
action()
}
}
}
OTHER UI THREAD CONCERNS
▸ Interesting topics for further study:
▸ Limit and manage coroutines via actors
▸ Dealing with event conflation
▸ Channel.CONFLATED
▸ Channel.UNLIMITED
LIBRARIES AND COROUTINES ON ANDROID
THREAD BLOCKING OPERATIONS AND THE UI
▸ CPU-intensive computations and/or API calls
▸ Can’t be done from UI thread or UI thread-confined coroutine
▸ Solution: suspending functions with execution context CommonPool
LIBRARIES AND COROUTINES ON ANDROID
suspend fun fib(x: Int): Int = run(CommonPool) {
fibBlocking(x)
}
fun fibBlocking(x: Int): Int =
if (x <= 1) 1 else fibBlocking(x - 1) + fibBlocking(x - 2)
NETWORK CALLS (I)
▸ Callback-free API call, handle offline-exceptions
LIBRARIES AND COROUTINES ON ANDROID
fun getUsers() : Deferred<List<Users>> {
return async(CommonPool) {
val request = Request.Builder().url(<SOMEURL>).build()
val response = OkHttpClient().newCall(request).execute()
// parse response...
}
}
NETWORK CALLS (II)
▸ Handle exceptions in calling code
▸ Use result object’s await() to obtain the data (suspending the coroutine)
▸ Use launch {…} builder to trigger execution of getUsers
LIBRARIES AND COROUTINES ON ANDROID
launch(UI) {
try {
val result = getUsers()
adapter.setElements(result.await())
...
} catch (exception: IOException){
// we’re offline
}
ANKO
▸ More often than not identified with declarative UI for Android/Kotlin
▸ But it also has APIs for:
▸ Async
▸ SQLite
▸ Anko 0.9 introduced naming changes around the Async API
▸ Since Anko 0.10, Anko has support for coroutines
LIBRARIES AND COROUTINES ON ANDROID
LIBRARIES AND COROUTINES ON ANDROID
COROUTINES IN ANKO
▸ Add anko-coroutines dependency
▸ Earlier versions of Anko already had support for async handling
▸ New:
▸ Coroutines in listeners
▸ bg()
▸ asReference()
fun getData(): Data { ... }
fun showData(data: Data) { ... }
async(UI) {
val data: Deferred<Data> = bg {
// Runs on the background
getData()
}
// This code is executed on the UI thread
showData(data.await())
}
LIBRARIES AND COROUTINES ON ANDROID
COROUTINES WITH ASYNCAWAIT
▸ Async/await approach
▸ Very rich library on top of Kotlin’s
coroutine core
▸ Plugins for Retrofit and rxJava
async {
val result = await {
//Long running code
}
// Use result
}
async {
val repos = await { github.getRepos() }
showList(repos)
repos.forEach { repo ->
val stats = await { github.getStats
(repo.name) }
showStats(repo, stats)
}
}
OTHER THINGS AND
FINAL THOUGHTS
https://www.flickr.com/photos/chrispiascik/4054331891
OTHER THINGS & FINAL THOUGHTS
UNIT TESTING SUSPENDING FUNCTIONS
▸ They need a coroutine to run, easiest way seems to be with runBlocking {…}
import kotlinx.coroutines.experimental.runBlocking
import org.testng.annotations.Test
class MyTest {
@Test
fun testMySuspendingFunction() = runBlocking<Unit> {
// your test code here
}
}
OTHER THINGS & FINAL THOUGHTS
EXPERIMENTAL?
▸ Coroutines are experimental in Kotlin 1.1.x, however:
▸ Very sound approach of dealing with concurrency
▸ Jetbrains guarantees backwards compatibility
▸ Potentially no forward compatibility
▸ Coroutines can and should be used in production
OTHER THINGS
RESOURCES
▸ Coroutines design document:

https://github.com/Kotlin/kotlin-coroutines
▸ Coroutines guide:

https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md
▸ Java Futures & Coroutines:

https://blog.frankel.ch/concurrency-java-futures-kotlin-coroutines/#gsc.tab=0
▸ Anko: 

https://github.com/Kotlin/anko
▸ AsyncAwait:

https://github.com/metalabdesign/AsyncAwait
OTHER THINGS
GET IN TOUCH
Kai Koenig
Email: kai@ventego-creative.co.nz
Work: http://www.ventego-creative.co.nz
Twitter: @AgentK
Telegram: @kaikoenig
Slides: http://www.slideshare.com/agentk

Kotlin Coroutines and Android sitting in a tree

  • 1.
    KOTLIN COROUTINES ANDANDROID SITTING IN A TREE... KAI KOENIG (@AGENTK)
  • 2.
    HELLO HELLO My name isKai! Software Architect in the web and mobile (Android) space 
 from New Zealand. Stuff I enjoy: Android, Kotlin, CFML, compilers and parsers, aviation and flying small aircraft, cats and chickens, Nintendo video games of all ages! Twitter: @AgentK
  • 3.
    AGENDA AGENDA ▸ Kotlin in5 minutes ▸ Why coroutines? ▸ Using coroutines in your Kotlin code ▸ Libraries and coroutines on Android
  • 4.
    KOTLIN IN 5MINUTES https://www.flickr.com/photos/tschiae/8080742303/
  • 5.
    HISTORY OF KOTLIN(I) ▸ Jetbrains wanted a more efficient JVM language when building products ▸ Looked at Scala, Groovy, etc. but came up with their own language spec ▸ First shown at the JVM Language Summit in 2011 ▸ Got some traction in Android-land in 2014 ▸ Modern language features (lambdas, HOF etc) but Java 6 byte code ▸ Low methods count (~7000) ▸ Strong focus on concision and an efficient, bloat-free language KOTLIN IN 5 MINUTES
  • 6.
    HISTORY OF KOTLIN(II) ▸ Since 1.0 release in early 2016: ▸ multiple maintenance releases ▸ now at 1.0.7 ▸ 1.1 was released in Feb 2017, ▸ currently at 1.1.51 (previously 1.1.5-1) KOTLIN IN 5 MINUTES
  • 7.
    HISTORY OF KOTLIN(III) ▸ At Google IO 2017, Kotlin became a first-grade language for Android ▸ Development of 1.2 is underway ▸ Java 9 compatibility ▸ Multiplatform projects ▸ Huge improvements to StdLib, type inference, smart cast etc. ▸ Strong community, lots of interesting frameworks, awesome support from Jetbrains KOTLIN IN 5 MINUTES
  • 8.
    KOTLIN IN 5MINUTES PROMINENT LANGUAGE FEATURES ▸ Immutability ▸ String templates ▸ Explicit null handling ▸ Properties and Fields ▸ Data classes ▸ Extension functions ▸ Syntactic sugar ▸ Type inference ▸ Lambdas ▸ Collection API ▸ Type-safe builders ▸ Java-Kotlin-Interop
  • 10.
    THE 1.1 RELEASE OVERVIEW ▸JavaScript target is not experimental anymore (browser & NodeJS) ▸ Full Kotlin language support ▸ Large part of the stdlib is supported ▸ Coroutines (JVM-only, experimental) ▸ Lightweight concurrency mechanism ▸ Alternative to threads ▸ Tooling improvements & more language features
  • 11.
  • 12.
    WHY COROUTINES? MOTIVATION ▸ Asynchronousprogramming is becoming increasingly important ▸ Problem: the need to avoid blocking introduces a lot of complexity ▸ Threads are: ▸ expensive to manage and limited ▸ complex in applications with lots of mutable state ▸ usually even more complex to deal with in UI-driven applications ▸ Callback hell (very common in Javascript)
  • 13.
  • 14.
    WHY COROUTINES? HISTORY ▸ Coroutineswere first mentioned and used in Simula 67 ▸ detach & resume keywords to suspend and then later resume execution ▸ Pushed aside by industry trend towards multi-threading ▸ C# has async/await ▸ Go was one of the first modern languages re-introducing coroutines
  • 15.
    WHY COROUTINES? COROUTINES INKOTLIN (I) ▸ Kotlin’s approach: Suspending functions ▸ Function/lambda that can be suspended and resumed ▸ No context-switching on the OS level ▸ Minimal integration into the core language and stdlib, most of functionality provided by libraries ▸ Design allows for a variety of asynchronous API methodologies to be implemented on top of Kotlin coroutines ▸ Supposed to feel like writing traditional code
  • 16.
    WHY COROUTINES? COROUTINES INKOTLIN (II) ▸ Easiest way to think about a coroutine is a very light-weighted thread ▸ They can run in parallel ▸ Coroutines can wait for each other ▸ They can communicate with each other ▸ Very, very cheap to create (compared to threads) ▸ A thread can run a lot of coroutines
  • 17.
    WHY COROUTINES? COROUTINES INKOTLIN (III) ▸ Multiple layers of libraries and integration points: ▸ Language support: suspending functions ▸ Low-level library in kotlinx.coroutines ▸ Mid-level library in kotlinx.coroutines ▸ High-level libraries (Anko etc.)
  • 18.
    USING COROUTINES IN YOURKOTLIN CODE https://www.flickr.com/photos/97114911@N05/14720054418
  • 19.
    USING COROUTINES INYOUR KOTLIN CODE FUNDAMENTALS ▸ Use Kotlin 1.1.4 as a minimum, better 1.1.51 ▸ Enable experimental feature in Gradle kotlin { experimental { coroutines 'enable' } } compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.2'
  • 20.
    USING COROUTINES INYOUR KOTLIN CODE “HELLO WORLD” ▸ launch {…} starts new coroutine on CommonPool thread pool ▸ delay() is a suspending function (not blocking a thread) fun main(args: Array<String>) { println("Start on main thread") launch(CommonPool) { delay(5000) println("Hello from coroutine") } Thread.sleep(10000) println("Stop on main thread") }
  • 21.
    USING COROUTINES INYOUR KOTLIN CODE “HELLO WORLD” IN BETTER ▸ Wait for the coroutines to finish - launch {…} returns a Job object fun main(args: Array<String>) = runBlocking { println("Start on main thread") val job = launch(CommonPool) { delay(5000) println("Hello from coroutine") } job.join() println("Stop on main thread") }
  • 22.
    USING COROUTINES INYOUR KOTLIN CODE THREADS VS COROUTINES import java.util.concurrent.atomic.AtomicInteger import kotlin.concurrent.thread fun main(args: Array<String>) { val c = AtomicInteger() for (i in 1..1_000_000) thread(start = true) { c.addAndGet(i) } println(c.get()) }
  • 23.
    import kotlinx.coroutines.experimental.* import java.util.concurrent.atomic.AtomicInteger funmain(args: Array<String>) { val c = AtomicInteger() for (i in 1..1_000_000) launch(CommonPool) { c.addAndGet(i) } // Temporary hack to allow the coroutines to finish Thread.sleep(2000) println(c.get()) } USING COROUTINES IN YOUR KOTLIN CODE THREADS VS COROUTINES
  • 24.
    USING COROUTINES INYOUR KOTLIN CODE ASYNC/AWAIT (I) ▸ async {…} starts new coroutine and returns a Deferred<T> object ▸ Deferred<T>.await() returns result of the coroutine ▸ await() needs to be called from inside a coroutine, because it needs to suspend in a non-blocking way ▸ Solution: wrap into runBlocking {…} coroutine ▸ Starts coroutine and wait until it’s finished
  • 25.
    USING COROUTINES INYOUR KOTLIN CODE ASYNC/AWAIT (II) import kotlinx.coroutines.experimental.* fun main(args: Array<String>) { val deferred = (1..1_000_000).map { n -> async (CommonPool) { n } } runBlocking { val sum = deferred.sumBy { it.await() } println("Sum: $sum") } }
  • 26.
    USING COROUTINES INYOUR KOTLIN CODE SUSPEND FUNCTIONS (I) ▸ Coroutines can suspend without blocking a thread ▸ Functions that might suspend need to be marked with the suspend keyword ▸ They can only be called from another suspend function or a coroutine
  • 27.
    USING COROUTINES INYOUR KOTLIN CODE SUSPEND FUNCTIONS (II) fun main(args: Array<String>) { val deferred = (1..1_000_000).map { n -> async (CommonPool) { doWork(n) } } runBlocking { ... } } suspend fun doWork(n: Int) : Int { delay(50) return n }
  • 28.
    USING COROUTINES INYOUR KOTLIN CODE BEHIND THE SCENES ▸ Kotlin coroutines are very light on language features: ▸ suspend the only new keyword added to the language and acts pretty much like a compiler flag ▸ Continuation and CoroutineContext in stdlib ▸ All the rest is in the kotlinx.coroutines library This makes the design of Kotlin coroutines very composable.
  • 29.
    USING COROUTINES INYOUR KOTLIN CODE MORE BEHIND THE SCENES ▸ At compilation: ▸ Suspending functions compile to functions with a general callback interface of type Continuation ▸ Code with suspension points compiles to state machine ▸ launch, runBlocking, async etc. are often called coroutine builders
  • 30.
    USING COROUTINES INYOUR KOTLIN CODE LAUNCH VS ASYNC ▸ Conceptually very similar ▸ launch {…} returns a Job, no resulting value ▸ async {…} returns a Deferred - a future that can be used to obtain a value ▸ async generally suited better in situations with independent concurrent flows
  • 31.
    USING COROUTINES INYOUR KOTLIN CODE WAITING AND CANCELLING ▸ cancel() and then join() can be used to terminate a coroutine execution early ▸ Job has an extension function cancelAndJoin() doing both at once val job = launch { repeat(1000) { i -> println("job: I'm sitting here and delaying $i ...") delay(500L) } } delay(1300L) println("main: I'm really over waiting!") job.cancel() job.join() // or use: job.cancelAndJoin() println("main: Let's go.")
  • 32.
    USING COROUTINES INYOUR KOTLIN CODE DEALING WITH TIMEOUTS ▸ Quite often the motivation for cancelling is a timeout: ▸ Track yourself via the Job instance ▸ Use withTimeout() {…} withTimeout(1300L) { repeat(1000) { i -> println("I'm waiting $i ...") delay(500L) } }
  • 33.
    USING COROUTINES INYOUR KOTLIN CODE THAT’S NOT ALL OF IT YET ▸ Coroutine context ▸ Coroutines and threads ▸ Channels ▸ Pipelines ▸ Dealing with state ▸ Shared (mutable) state & Actors Compare Coroutines with Java Futures API
  • 34.
  • 35.
    MOTIVATION ▸ In general,UI-driven apps need to be aware of long-running processes ▸ In Android specifically, we can’t do any networking on the UI thread. ▸ The kotlinx.coroutines library by Jetbrains provides a starting point for Android, too. LIBRARIES AND COROUTINES ON ANDROID compile 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.19.2'
  • 36.
    UI CONTEXT ▸ TheAndroid library provides access to a coroutine context for the UI thread ▸ Coroutine launches in UI thread, UI updates and suspending functions are possible ▸ Non-blocking, UI is not frozen LIBRARIES AND COROUTINES ON ANDROID launch(UI) { for (i in 10 downTo 1) { hello.text = "Countdown $i ..." delay(500) } hello.text = "Done!" }
  • 37.
    OTHER UI THREADCONCERNS ▸ For Jobs and cancelling coroutines, the same general principles still apply ▸ using launch {…} provides a reference to a Job ▸ can be cancelled with cancel() - for instance via UI control ▸ In UI scenarios useful to write own coroutines builders as extension functions LIBRARIES AND COROUTINES ON ANDROID button.onClick { ... } fun View.onClick(action: suspend () -> Unit) { setOnClickListener { launch(UI) { action() } } }
  • 38.
    OTHER UI THREADCONCERNS ▸ Interesting topics for further study: ▸ Limit and manage coroutines via actors ▸ Dealing with event conflation ▸ Channel.CONFLATED ▸ Channel.UNLIMITED LIBRARIES AND COROUTINES ON ANDROID
  • 39.
    THREAD BLOCKING OPERATIONSAND THE UI ▸ CPU-intensive computations and/or API calls ▸ Can’t be done from UI thread or UI thread-confined coroutine ▸ Solution: suspending functions with execution context CommonPool LIBRARIES AND COROUTINES ON ANDROID suspend fun fib(x: Int): Int = run(CommonPool) { fibBlocking(x) } fun fibBlocking(x: Int): Int = if (x <= 1) 1 else fibBlocking(x - 1) + fibBlocking(x - 2)
  • 40.
    NETWORK CALLS (I) ▸Callback-free API call, handle offline-exceptions LIBRARIES AND COROUTINES ON ANDROID fun getUsers() : Deferred<List<Users>> { return async(CommonPool) { val request = Request.Builder().url(<SOMEURL>).build() val response = OkHttpClient().newCall(request).execute() // parse response... } }
  • 41.
    NETWORK CALLS (II) ▸Handle exceptions in calling code ▸ Use result object’s await() to obtain the data (suspending the coroutine) ▸ Use launch {…} builder to trigger execution of getUsers LIBRARIES AND COROUTINES ON ANDROID launch(UI) { try { val result = getUsers() adapter.setElements(result.await()) ... } catch (exception: IOException){ // we’re offline }
  • 42.
    ANKO ▸ More oftenthan not identified with declarative UI for Android/Kotlin ▸ But it also has APIs for: ▸ Async ▸ SQLite ▸ Anko 0.9 introduced naming changes around the Async API ▸ Since Anko 0.10, Anko has support for coroutines LIBRARIES AND COROUTINES ON ANDROID
  • 43.
    LIBRARIES AND COROUTINESON ANDROID COROUTINES IN ANKO ▸ Add anko-coroutines dependency ▸ Earlier versions of Anko already had support for async handling ▸ New: ▸ Coroutines in listeners ▸ bg() ▸ asReference() fun getData(): Data { ... } fun showData(data: Data) { ... } async(UI) { val data: Deferred<Data> = bg { // Runs on the background getData() } // This code is executed on the UI thread showData(data.await()) }
  • 44.
    LIBRARIES AND COROUTINESON ANDROID COROUTINES WITH ASYNCAWAIT ▸ Async/await approach ▸ Very rich library on top of Kotlin’s coroutine core ▸ Plugins for Retrofit and rxJava async { val result = await { //Long running code } // Use result } async { val repos = await { github.getRepos() } showList(repos) repos.forEach { repo -> val stats = await { github.getStats (repo.name) } showStats(repo, stats) } }
  • 45.
    OTHER THINGS AND FINALTHOUGHTS https://www.flickr.com/photos/chrispiascik/4054331891
  • 46.
    OTHER THINGS &FINAL THOUGHTS UNIT TESTING SUSPENDING FUNCTIONS ▸ They need a coroutine to run, easiest way seems to be with runBlocking {…} import kotlinx.coroutines.experimental.runBlocking import org.testng.annotations.Test class MyTest { @Test fun testMySuspendingFunction() = runBlocking<Unit> { // your test code here } }
  • 47.
    OTHER THINGS &FINAL THOUGHTS EXPERIMENTAL? ▸ Coroutines are experimental in Kotlin 1.1.x, however: ▸ Very sound approach of dealing with concurrency ▸ Jetbrains guarantees backwards compatibility ▸ Potentially no forward compatibility ▸ Coroutines can and should be used in production
  • 48.
    OTHER THINGS RESOURCES ▸ Coroutinesdesign document:
 https://github.com/Kotlin/kotlin-coroutines ▸ Coroutines guide:
 https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md ▸ Java Futures & Coroutines:
 https://blog.frankel.ch/concurrency-java-futures-kotlin-coroutines/#gsc.tab=0 ▸ Anko: 
 https://github.com/Kotlin/anko ▸ AsyncAwait:
 https://github.com/metalabdesign/AsyncAwait
  • 49.
    OTHER THINGS GET INTOUCH Kai Koenig Email: [email protected] Work: http://www.ventego-creative.co.nz Twitter: @AgentK Telegram: @kaikoenig Slides: http://www.slideshare.com/agentk