Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Coroutines 101

Kotlin Coroutines 101

As the title suggests this is a complete 101 guide to Kotlin coroutine. The talk will cover the basics of coroutines and how to get started with them. We will look at how to incorporate coroutines in your applications. We will also look at why coroutines are better for asynchronous programming and what other solutions exist today for achieving async and their pain-points.

Sagar Viradiya

August 24, 2019
Tweet

More Decks by Sagar Viradiya

Other Decks in Programming

Transcript

  1. Coroutines 101 A Newbie guide to coroutines @viradiya_sagar

  2. What is Coroutine? Coroutines are lightweight threads which allows to

    write async code in sequential manner.
  3. None
  4. What is Coroutine? 1. Coroutines are like lightweight threads. 2.

    Allows to write async code in sequential manner.
  5. Why Async?

  6. Main thread (UI thread) View Inflation Measure + Layout Draw

    Many more things... Your code
  7. Refresh Rate 60 HZ ~16 ms

  8. Refresh Rate 90 HZ ~12 ms

  9. Refresh Rate 120 HZ ~8.3 ms

  10. How Async ?

  11. Callback Display list of tweets 1. Get token 2. Get

    list of tweets
  12. fun getToken(cb: (Token) -> Unit) { //Makes a request for

    token, invokes callback when done //returns immediately } fun getTweets(token: Token, cb: (List<Tweet>) -> Unit) { //Makes a request for tweets, invokes callback when done //returns immediately }
  13. fun displayTweets() { getToken { token -> getTweets(token) { tweets

    -> //Consume list of tweets } } }
  14. Callback Display list of tweets 1. Get token 2. Get

    list of tweets 3. Process tweets
  15. fun getToken(cb: (Token) -> Unit) { //Makes a request for

    token, invokes callback when done //returns immediately } fun getTweets(token: Token, cb: (List<Tweet>) -> Unit) { //Makes a request for tweets, invokes callback when done //returns immediately } fun processTweets(tweets: List<Tweet>, cb: (List<Tweet>) -> Unit) { //Process list of tweet, invoke callback when done //returns immediately }
  16. fun displayTweets() { getToken { token -> getTweets(token) { tweets

    -> processTweets(tweets) { tweets -> //Consume tweets } } } }
  17. None
  18. Reactive programming fun displayTweets() { val disposable = getToken() .flatMap(token:

    Token) { return getTweets(token) } .map(tweets: List<Tweet>) { //Perform processing } .subscribe( tweets -> { //Consume tweets }, throwable -> { //Handle error } ) }
  19. Coroutines way to Async suspend fun getToken(): Token { //Get

    token from n/w call return token } suspend fun getTweet(token: Token): List<Tweet> { //Get tweets using token from n/w call return tweets } suspend fun processTweet(tweets: List<Tweet>): List<Tweet> { //Perform processing on list return updatedTweets }
  20. suspend fun displayTweets() { val token = getToken() val tweets

    = getTweets(token) val updatedTweets = processTweets(tweets) //Consume updatedTweets }
  21. Coroutines 1. Coroutines are like light weight threads. 2. It

    allows you to write async code in sequential manner.
  22. fun main() = runBlocking { repeat(100_000) { // launch a

    lot of coroutines launch { delay(1000L) print(".") } } }
  23. Suspending function Non blocking function Suspends the execution of coroutine

    and resumes execution. Concept of continuation.
  24. None
  25. suspend fun displayTweets() { val token = getToken() val tweets

    = getTweets(token) val updatedTweets = processTweets(tweets) //Consume updatedTweets }
  26. ync suspend fun getToken(): Token { //Get token from n/w

    call return token } suspend fun getTweet(token: Token): List<Tweet> { //Get tweets using token from n/w call return tweets } suspend fun processTweet(tweets: List<Tweet>): List<Tweet> { //Perform processing on list return updatedTweets }
  27. Concept of continuation void getToken(Continuation<Token> continuation) { //Get token from

    n/w call continuation.resume(token) } void getTweets(Token token, Continuation<List<Tweet>> continuation) { //Get tweets using token from n/w call continuation.resume(tweets) } void processTweets(List<Tweet> tweets, Continuation<List<Tweet>> continuation) { //Perform processing on list continuation.resume(updatedTweets) }
  28. interface Continuation<in T> { val context: CoroutineContext fun resume(value: T)

    fun resumeWithException(exception: Throwable) }
  29. Coroutine scope Lifecycle of coroutine Scope encapsulate coroutine context.

  30. public interface CoroutineScope { public val coroutineContext: CoroutineContext }

  31. GlobalScope.launch { // launch new coroutine in background and continue

    delay(1000L) // non-blocking delay for 1 second (default time unit is ms) println("Hello World!") // print after delay }
  32. class MainActivity : AppCompatActivity(), CoroutineScope { private lateinit var job:

    Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() runTask() ... } fun runTask() { launch { //Perform task here } } override fun onDestroy() { job.cancel() super.onDestroy() } }
  33. Coroutine context Job Dispatcher Coroutine name Exception handler

  34. Coroutine builders Launch Async runBlocking

  35. Launch fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart =

    CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job
  36. Launch val job = GlobalScope.launch { // launch new coroutine

    in background and continue delay(1000L) // non-blocking delay for 1 second (default time unit is ms) println("Hello World!") // print after delay } . . . job.cancel()
  37. Async - Await Use for concurrent tasks which are independent

    of each other. Await - Suspending function to get result from async.
  38. Async fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart

    = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T>
  39. suspend fun displayTweets() { val token = getToken() val tweets1

    : Deferred<List<Tweet>> = async(Dispatchers.Default) { getTweets(token, "#IPL") } val tweets2 : Deferred<List<Tweet>> = async(Dispatchers.Default) { getTweets(token, "#EPL") } val updatedTweets = processTweets(tweets1.await() + tweets2.await()) //Consume updatedTweets }
  40. runBlocking Blocks the current thread until coroutine completes. Useful in

    unit testing.
  41. fun main() = runBlocking<Unit> { // start main coroutine GlobalScope.launch

    { // launch new coroutine in background and continue delay(1000L) println("World!") } println("Hello,") // main coroutine continues here immediately }
  42. Coroutine dispatcher Dispatcher.Default Dispatcher.IO Dispatcher.Unconfined Dispatcher.Main (Need separate dependency for

    each UI framework)
  43. coroutineScope withContext Scoping functions

  44. coroutineScope Designed for parallel decomposition of work. suspend fun doThingsParallelly()

    = coroutineScope { val result1 = async { //Task1 } val result2 = async { //Task2 } result1.await() + result2.await() }
  45. withContext Mostly for thread switching. launch { mainScope -> .

    . . val result = withContext(Dispatcher.Default) { //Perform heavy task here } . . . }
  46. Summary 1. Need for async programming. 2. Ways to achieve

    async programming. 3. Suspending functions. 4. Coroutines scope. 5. Coroutines context. 6. Coroutines builders. 7. Coroutines dispatchers. 8. Scoping functions.
  47. Resources Kotlin official doc - https://kotlinlang.org/docs/reference/coroutines/basics.html Blog post - https://antonioleiva.com/coroutines/

    Videos • KotlinConf 2018 - Exploring Coroutines in Kotlin by Venkat Subramariam https://youtu.be/jT2gHPQ4Z1Q • KotlinConf 2017 - Introduction to Coroutines by Roman Elizarov https://youtu.be/_hfBv0a09Jc • KotlinConf 2018 - Android Suspenders by Chris Banes https://youtu.be/P7ov_r1JZ1g
  48. Thank you !

  49. Questions ?