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

Using Kotlin Coroutines on Android

Using Kotlin Coroutines on Android

Adora Nwodo

June 08, 2019
Tweet

More Decks by Adora Nwodo

Other Decks in Programming

Transcript

  1. Hi, I’m Adora Software Engineer Creator of AdoraHack Women Techmakers

    Ajah Ambassador FSDLagos & Android Ngr Co-organizer Twitter, @theadoranwodo
  2. What we want to do val order = fetchOrderDetails() textView.text

    = order.code Never block the main thread
  3. A Solution fetchOrderDetails{ order -> textView.text = order.code } Lots

    of memory leaks Also very difficult to read. We don’t want callback hell :(
  4. A Nightmare fetchOrderDetails{ order -> textView.text = order.code someDbTransaction{ db_res

    -> anotherCallback{ res -> saveToFile{ res -> // and it continues ... } } } }
  5. Let’s try Coroutines Coroutines are lightweight threads. Anti callbacks. Write

    code sequentially. Makes code easier to read. We can have much more coroutines as opposed to threads. Coroutine mechanism: suspend and resume. Declare a very heavy task as a suspend function
  6. Let’s try Coroutines - suspend function suspend fun fetchOrderDetails(): Order

    { … } suspend fun doSomething() { val order = fetchOrderDetails() textView.text = order.code }
  7. Where can I call a suspend function? In another suspend

    function’ In coroutine builders (e,g, async, launch) In suspend lambdas In coroutine scopes
  8. WorkManager WorkManager provides a unified API for background work taking

    battery and compatibility across Android versions to account. - Worker - CoroutineWorker - RxWorker - ListenableWorker
  9. WorkManager & Coroutines dependencies { def work_version = "2.0.1" //

    Kotlin + coroutines implementation "androidx.work:work-runtime-ktx:$work_version" } Snippet from: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/coroutineworker.html
  10. WorkManager & Coroutines class CoroutineDownloadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context,

    params) { override val coroutineContext = Dispatchers.IO override suspend fun doWork(): Result = coroutineScope { val jobs = (0 until 100).map { async { downloadSynchronously("https://www.google.com") } } // awaitAll will throw an exception if a download fails, which CoroutineWorker will treat as a failure jobs.awaitAll() Result.success() } } Snippet from: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/coroutineworker.html
  11. Coroutine leaks To deal with Coroutine leaks, Kotlin introduced Coroutine

    scopes. A scope is a way to keep track of coroutines. Coroutines run in a scope and the scope has the ability to cancel all the coroutines inside it. Use scopes to avoid leaks. Structured concurrency.
  12. viewModelScope Coroutines are useful here when there is work that

    should be done only when the ViewModel is active. class MyViewModel: ViewModel() { init { viewModelScope.launch { // Coroutine that will be canceled when the ViewModel is cleared. } } }
  13. LifecycleScope A LifecycleScope is defined for each Lifecycle object. Any

    coroutine launched in this scope is canceled when the Lifecycle is destroyed. You can access the Lifecycle’s CoroutineScope either via lifecycle.coroutineScope or lifecycleOwner.lifecycleScope properties. LifecycleOwner could be an Activity or a Fragment.
  14. liveData LiveData is an observable value holder for UI It

    is now interoperable with Coroutines Compute value in Coroutine and serve as LiveData
  15. liveData val user = liveData { val data = database.loadUser()

    // loadUser is a suspend function. emit(data) } - Use the liveData builder function to call a suspend function asynchronously, - use emit() to emit the result:
  16. Testing Coroutines val testDispatcher = TestCoroutineDispatcher() val testScope = TestCoroutineScope(testDispatcher)

    @Before fun setup(){ Dispatchers.setMain(testDispatcher) } @After fun tearDown(){ Dispatchers.resetMain() testScope.cleanupTestCoroutines() }
  17. Testing Coroutines @get: Rule val testCoroutineRule = TestCoroutineRule() @Test fun

    testSomething() = testCoroutineRule.runBlockingTest { // test code here }