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

Better Async with Kotlin Coroutines

Adit Lal
October 09, 2018

Better Async with Kotlin Coroutines

This talk will highlight the benefits to using coroutines over other solutions to do asynchronous programming with Kotlin on Android. The talk would also introduce how to use kotlin coroutines in our apps.

Adit Lal

October 09, 2018
Tweet

More Decks by Adit Lal

Other Decks in Technology

Transcript

  1. Problem statement @WorkerThread fun loadWeather(city: String): List<Weather> { … }

    @MainThread fun showWeather(weather: List<Weather>) { … }
  2. Thread { code } .start() object MyTask: AsyncTask() { override

    fun doInBackground { code } override fun onPostExecute { code } } Current Callbacks
  3. Corountines It can be thought of as an instance of

    suspend-able computation non-blocking code Coroutines simplify asynchronous programming by providing possibility to write code in direct style (sequentially).
  4. Coroutine Example launch { println("CR start : ${getThreadName()}") Thread.sleep(100) println("CR

    ended : ${getThreadName()}") } run { println("Run start: ${getThreadName()}") Thread.sleep(300) println("Run ended: ${getThreadName()}") } fun funExperiment() { }
  5. Run start: main CR start : commonPool-worker-1 Output Coroutine Example

    launch { println("CR start : ${getThreadName()}") Thread.sleep(100) println("CR ended : ${getThreadName()}") } run { println("Run start: ${getThreadName()}") Thread.sleep(300) println("Run ended: ${getThreadName()}") } fun funExperiment() { }
  6. CR ended : commonPool-worker-1 Run ended: main Output Coroutine Example

    launch { println("CR start : ${getThreadName()}") Thread.sleep(100) println("CR ended : ${getThreadName()}") } run { println("Run start: ${getThreadName()}") Thread.sleep(300) println("Run ended: ${getThreadName()}") } } Run start: main CR start : commonPool-worker-1 fun funExperiment() {
  7. interface Continuation<in T> { val context: CoroutineContext fun resume(value: T)

    fun resumeWithException(exception: Throwable) } Continuation Components
  8. T withContext() Job launch() Deferred async() Returns result Uncaught exception

    - crash Fire and forget Uncaught exception - crash Non-Blocking future Uncaught exception - returned inside deferred Components
  9. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  10. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  11. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  12. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  13. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  14. public actual fun launch( context: CoroutineContext = DefaultDispatcher, start: CoroutineStart

    = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Job Builders
  15. The plan 1. start coroutine 2. var apiData = fetchDataFromServer().await()

    3. var result = parseData(apiData).await() 4. displayInList(data) 5. DSL
  16. val job = launch(context = CommonPool) { val weatherResult =

    loadWeather("Bengaluru") launch(context = UI) { showWeather(weatherResult) } } API and then show results
  17. Another Coroutine API and then show results val job =

    launch(context = CommonPool) { val weatherResult = loadWeather("Bengaluru") launch(context = UI) { showWeather(weatherResult) } }
  18. job.cancel() //cancels the execution of parent and child coroutines val

    job = launch(context = CommonPool) { val weatherResult = loadWeather("Bengaluru") launch(context = UI) { showWeather(weatherResult) } } API and then show results
  19. • Simpler thread switching • Simple DSL • Dancing with

    final code Coroutines The Fun Solution
  20. Solution fun getWeather(city="Bengaluru") { async(context = UI) { view.showLoading() val

    result = withContext(bgContext) { loadWeather(city) } showWeather(result) } }
  21. Solution fun getWeather(city="Bengaluru") { launch(context = UI) { view.showLoading() val

    result = withContext(bgContext) { loadWeather(city) } showWeather(result) } }
  22. Solution fun getWeather(city="Bengaluru") { launch(context = UI) { view.showLoading() val

    result = withContext(bgContext) { loadWeather(city) } showWeather(result) } }
  23. Solution fun getWeather(city="Bengaluru") { launch(context = UI) { view.showLoading() val

    result = withContext(bgContext) { loadWeather(city) } showWeather(result) } }
  24. Where we were @WorkerThread fun loadWeather(city: String): List<Weather> { …

    } @MainThread fun showWeather(weather: List<Weather>) { … }
  25. Solution fun getWeather(city="Bengaluru") { launch(context = UI) { view.showLoading() val

    result = withContext(bgContext) { loadWeather(city) } showWeather(result) } }
  26. Fun DSL’s suspend fun <T> load(block: () -> T): Deferred<T>

    { } return block() fun <T> Deferred<T>.thenOnUI(uiFunction: (T) -> Unit) { } launch(UI) { uiFunction([email protected]()) }