KOTLIN COROUTINES AND ANDROID SITTING IN A TREE... KAI KOENIG (@AGENTK)
#droidconVN 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! Follow me on Twitter: @AgentK
#droidconVN AGENDA AGENDA ▸ Kotlin in 3 minutes ▸ Why coroutines? ▸ Using coroutines in your Kotlin code ▸ Libraries and coroutines on Android
KOTLIN IN 3 MINUTES https://www.flickr.com/photos/tschiae/8080742303/
#droidconVN 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 3 MINUTES
#droidconVN 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.60 ▸ experimental new feature: Kotlin coroutines KOTLIN IN 3 MINUTES
#droidconVN HISTORY OF KOTLIN (III) ▸ At Google IO 2017, Kotlin became a first-grade language for Android ▸ Release of 1.2 happened in late 2017 (CHECK) ▸ 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 3 MINUTES
#droidconVN 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
WHY COROUTINES? https://www.flickr.com/photos/61299367@N05/9448165205
#droidconVN 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)
#droidconVNhttp://slides.com/michaelholroyd/asyncnodejs/#/
#droidconVN 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 (language-level keywords) ▸ Go was one of the first modern languages re-introducing coroutines
#droidconVN WHY COROUTINES? COROUTINES IN KOTLIN (I) ▸ Kotlin’s approach: Suspending functions ▸ Function/lambda that can be suspended and resumed ▸ Requires 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
#droidconVN 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
#droidconVN WHY COROUTINES? COROUTINES IN KOTLIN (III) ▸ Multiple layers of libraries and integration points: ▸ Language support: suspending functions ▸ Low-level library & generators in kotlin.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
#droidconVN USING COROUTINES IN YOUR KOTLIN CODE FUNDAMENTALS ▸ Kotlin 1.1.4 is the absolute minimum, better 1.1.50+ or right away latest 1.2 ▸ Enable experimental feature in Gradle kotlin { experimental { coroutines 'enable' } } compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'
#droidconVN 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") } println("Hello from main thread") Thread.sleep(10000) println("Stop on main thread") }
#droidconVN 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") } println("Hello from main thread") job.join() println("Stop on main thread") }
#droidconVN USING COROUTINES IN YOUR KOTLIN CODE THREADS VS COROUTINES fun main(args: Array<String>) { val jobs = List(10_000) { thread(start = true) { Thread.sleep(1000L) print(".") } } jobs.forEach { it.join() } }
#droidconVN USING COROUTINES IN YOUR KOTLIN CODE THREADS VS COROUTINES fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(10_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } }
#droidconVN 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
#droidconVN USING COROUTINES IN YOUR KOTLIN CODE ASYNC/AWAIT (II) fun main(args: Array<String>) { val deferred = (1..60_000).map { n -> async (CommonPool) { n } } runBlocking { val sum = deferred.sumBy { it.await() } println("Sum: $sum") } }
#droidconVN 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
#droidconVN 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 }
#droidconVN 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.
#droidconVN 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 a state machine ▸ launch, runBlocking, async etc. are often called coroutine builders
#droidconVN 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
#droidconVN 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.")
#droidconVN 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) } }
#droidconVN USING COROUTINES IN YOUR KOTLIN CODE THAT’S NOT ALL OF IT YET ▸ Coroutine contexts ▸ 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/
#droidconVN MOTIVATION ▸ In general, UI-driven apps need to be aware of long-running processes ▸ Android specifically: ▸ we can’t do any networking on the UI thread ▸ we need to avoid long-running operations due to ANRs ▸ 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.22.5'
#droidconVN 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!" }
#droidconVN 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() } } }
#droidconVN 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
#droidconVN 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)
#droidconVN 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... } }
#droidconVN 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 }
#droidconVN 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
#droidconVN 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()) }
#droidconVN 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) } }
#droidconVN LIBRARIES AND COROUTINES ON ANDROID COROUTINES AND RXJAVA (I) ▸ There is an interop library for RX2 with coroutines: org.jetbrains.kotlinx:kotlinx- coroutines-rx2 ▸ rxJava -> coroutines: openSubscription(), awaitFirstOrDefault() ▸ coroutines -> rxJava: ▸ Job.asCompletable, Deferred.asSingle() ▸ Multiple coroutine builders: rxMaybe, rxCompletable etc.
#droidconVN LIBRARIES AND COROUTINES ON ANDROID COROUTINES AND RXJAVA (II) ▸ Method count: ▸ Coroutines ~10-20% less than rxJava ▸ APK size: ▸ Similar, ~10-20% smaller than with rxJava ▸ Interop libraries add quite a lot to method count and APK size.
OTHER THINGS AND FINAL THOUGHTS https://www.flickr.com/photos/chrispiascik/4054331891
#droidconVN 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 } }
#droidconVN OTHER THINGS & FINAL THOUGHTS EXPERIMENTAL? ▸ Coroutines are currently experimental in Kotlin 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 ▸ Quite low learning curve compared to rxJava and other libraries
#droidconVN OTHER THINGS RESOURCES ▸ Introduction to background processing in Android:
 http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html ▸ 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 ▸ Coroutines and reactive streams:
 https://github.com/Kotlin/kotlinx.coroutines/blob/master/reactive/README.md
#droidconVN 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 - 2018 version

  • 1.
    KOTLIN COROUTINES ANDANDROID SITTING IN A TREE... KAI KOENIG (@AGENTK)
  • 2.
    #droidconVN 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! Follow me on Twitter: @AgentK
  • 3.
    #droidconVN AGENDA AGENDA ▸ Kotlin in3 minutes ▸ Why coroutines? ▸ Using coroutines in your Kotlin code ▸ Libraries and coroutines on Android
  • 4.
    KOTLIN IN 3MINUTES https://www.flickr.com/photos/tschiae/8080742303/
  • 5.
    #droidconVN 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 3 MINUTES
  • 6.
    #droidconVN 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.60 ▸ experimental new feature: Kotlin coroutines KOTLIN IN 3 MINUTES
  • 7.
    #droidconVN HISTORY OF KOTLIN(III) ▸ At Google IO 2017, Kotlin became a first-grade language for Android ▸ Release of 1.2 happened in late 2017 (CHECK) ▸ 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 3 MINUTES
  • 8.
    #droidconVN 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
  • 9.
  • 10.
    #droidconVN 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)
  • 11.
  • 12.
    #droidconVN 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 (language-level keywords) ▸ Go was one of the first modern languages re-introducing coroutines
  • 13.
    #droidconVN WHY COROUTINES? COROUTINES INKOTLIN (I) ▸ Kotlin’s approach: Suspending functions ▸ Function/lambda that can be suspended and resumed ▸ Requires 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
  • 14.
    #droidconVN 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
  • 15.
    #droidconVN WHY COROUTINES? COROUTINES INKOTLIN (III) ▸ Multiple layers of libraries and integration points: ▸ Language support: suspending functions ▸ Low-level library & generators in kotlin.coroutines ▸ Mid-level library in kotlinx.coroutines ▸ High-level libraries (Anko etc.)
  • 16.
    USING COROUTINES IN YOURKOTLIN CODE https://www.flickr.com/photos/97114911@N05/14720054418
  • 17.
    #droidconVN USING COROUTINES INYOUR KOTLIN CODE FUNDAMENTALS ▸ Kotlin 1.1.4 is the absolute minimum, better 1.1.50+ or right away latest 1.2 ▸ Enable experimental feature in Gradle kotlin { experimental { coroutines 'enable' } } compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'
  • 18.
    #droidconVN 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") } println("Hello from main thread") Thread.sleep(10000) println("Stop on main thread") }
  • 19.
    #droidconVN 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") } println("Hello from main thread") job.join() println("Stop on main thread") }
  • 20.
    #droidconVN USING COROUTINES INYOUR KOTLIN CODE THREADS VS COROUTINES fun main(args: Array<String>) { val jobs = List(10_000) { thread(start = true) { Thread.sleep(1000L) print(".") } } jobs.forEach { it.join() } }
  • 21.
    #droidconVN USING COROUTINES INYOUR KOTLIN CODE THREADS VS COROUTINES fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(10_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } }
  • 22.
    #droidconVN 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
  • 23.
    #droidconVN USING COROUTINES INYOUR KOTLIN CODE ASYNC/AWAIT (II) fun main(args: Array<String>) { val deferred = (1..60_000).map { n -> async (CommonPool) { n } } runBlocking { val sum = deferred.sumBy { it.await() } println("Sum: $sum") } }
  • 24.
    #droidconVN 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
  • 25.
    #droidconVN 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 }
  • 26.
    #droidconVN 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.
  • 27.
    #droidconVN 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 a state machine ▸ launch, runBlocking, async etc. are often called coroutine builders
  • 28.
    #droidconVN 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
  • 29.
    #droidconVN 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.")
  • 30.
    #droidconVN 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) } }
  • 31.
    #droidconVN USING COROUTINES INYOUR KOTLIN CODE THAT’S NOT ALL OF IT YET ▸ Coroutine contexts ▸ Coroutines and threads ▸ Channels ▸ Pipelines ▸ Dealing with state ▸ Shared (mutable) state & Actors Compare Coroutines with Java Futures API
  • 32.
  • 33.
    #droidconVN MOTIVATION ▸ In general,UI-driven apps need to be aware of long-running processes ▸ Android specifically: ▸ we can’t do any networking on the UI thread ▸ we need to avoid long-running operations due to ANRs ▸ 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.22.5'
  • 34.
    #droidconVN 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!" }
  • 35.
    #droidconVN 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() } } }
  • 36.
    #droidconVN 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
  • 37.
    #droidconVN 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)
  • 38.
    #droidconVN 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... } }
  • 39.
    #droidconVN 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 }
  • 40.
    #droidconVN 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
  • 41.
    #droidconVN 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()) }
  • 42.
    #droidconVN 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) } }
  • 43.
    #droidconVN LIBRARIES AND COROUTINESON ANDROID COROUTINES AND RXJAVA (I) ▸ There is an interop library for RX2 with coroutines: org.jetbrains.kotlinx:kotlinx- coroutines-rx2 ▸ rxJava -> coroutines: openSubscription(), awaitFirstOrDefault() ▸ coroutines -> rxJava: ▸ Job.asCompletable, Deferred.asSingle() ▸ Multiple coroutine builders: rxMaybe, rxCompletable etc.
  • 44.
    #droidconVN LIBRARIES AND COROUTINESON ANDROID COROUTINES AND RXJAVA (II) ▸ Method count: ▸ Coroutines ~10-20% less than rxJava ▸ APK size: ▸ Similar, ~10-20% smaller than with rxJava ▸ Interop libraries add quite a lot to method count and APK size.
  • 45.
    OTHER THINGS AND FINALTHOUGHTS https://www.flickr.com/photos/chrispiascik/4054331891
  • 46.
    #droidconVN 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.
    #droidconVN OTHER THINGS &FINAL THOUGHTS EXPERIMENTAL? ▸ Coroutines are currently experimental in Kotlin 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 ▸ Quite low learning curve compared to rxJava and other libraries
  • 48.
    #droidconVN OTHER THINGS RESOURCES ▸ Introductionto background processing in Android:
 http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html ▸ 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 ▸ Coroutines and reactive streams:
 https://github.com/Kotlin/kotlinx.coroutines/blob/master/reactive/README.md
  • 49.
    #droidconVN OTHER THINGS GET INTOUCH 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