O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Kotlin Coroutines and Android sitting in a tree - 2018 version

226 visualizações

Publicada em

Since the release of Kotlin 1.1 there is now the language feature of Kotlin Coroutines available for use in Java and Android projects. Coroutines are a new way to write asynchronous and non-blocking code. They can be thought of as light-weight threads without having to deal with all the problems that threads bring to the table.

A lot of developers think that Kotlin Coroutines are mainly or only useful for Kotlin on the JVM, but that’s not true. There are a variety of use cases in which the application of Coroutines can make a lot of sense on Android.

This talk is introducing the ideas behind Kotlin Coroutines, showing how to use them in Kotlin code for both the JVM and Android via the kotlinx-coroutines APIs and then exploring specific applications in Android. Part of this is a deeper look into the use of Coroutines in higher-level frameworks such as AsyncAwait and Anko and how they stack up against other concepts of asynchrony such as rxJava.

Publicada em: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui

Kotlin Coroutines and Android sitting in a tree - 2018 version

  2. 2. #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
  3. 3. #droidconVN AGENDA AGENDA ▸ Kotlin in 3 minutes ▸ Why coroutines? ▸ Using coroutines in your Kotlin code ▸ Libraries and coroutines on Android
  4. 4. KOTLIN IN 3 MINUTES https://www.flickr.com/photos/tschiae/8080742303/
  5. 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. 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. 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. 8. #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
  9. 9. WHY COROUTINES? https://www.flickr.com/photos/61299367@N05/9448165205
  10. 10. #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)
  11. 11. #droidconVNhttp://slides.com/michaelholroyd/asyncnodejs/#/
  12. 12. #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
  13. 13. #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
  14. 14. #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
  15. 15. #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.)
  16. 16. USING COROUTINES IN YOUR KOTLIN CODE https://www.flickr.com/photos/97114911@N05/14720054418
  17. 17. #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'
  18. 18. #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") }
  19. 19. #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") }
  20. 20. #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() } }
  21. 21. #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() } }
  22. 22. #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
  23. 23. #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") } }
  24. 24. #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
  25. 25. #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 }
  26. 26. #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.
  27. 27. #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
  28. 28. #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
  29. 29. #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.")
  30. 30. #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) } }
  31. 31. #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
  32. 32. LIBRARIES AND COROUTINES ON ANDROID https://www.flickr.com/photos/qiaomeng/4665885561/
  33. 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. 34. #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!" }
  35. 35. #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() } } }
  36. 36. #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
  37. 37. #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)
  38. 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. 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. 40. #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
  41. 41. #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()) }
  42. 42. #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) } }
  43. 43. #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.
  44. 44. #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.
  45. 45. OTHER THINGS AND FINAL THOUGHTS https://www.flickr.com/photos/chrispiascik/4054331891
  46. 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. 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. 48. #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:
  49. 49. #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