Coroutines in Just 5 Minutes | Complete Android Coroutine Best Practices

Puneet Grover
6 min readApr 24, 2021

“The beautiful thing about learning is that nobody can take it away from you.” — B.B. King

Howdy guys, Today I’m going to write Article on Coroutines But this will be different from all other articles as here I’ll write COMPLETE tutorial on Coroutines in just 5 Minutes like InShorts News App

So if you want a complete wrap up on Coroutines, You’re at a Right Place!

Let’s Start 🤘

WHAT IS COROUTINE?

Coroutines API allows us to write asynchronous code in a sequential manner

It avoids unnecessary boilerplate codes comes with callbacks (callback hells) and makes our code more readable and maintainable

Our First coroutine/Launch A Coroutine

CoroutineScope -> Interface which provides scope of coroutine

  • Pass context (IO/Main) in scope
  • Example — CoroutineScope(Dispatchers.IO).launch{}
  • All coroutines going to start in this scope will run on this context
  • Launch is coroutine builder; this will create coroutine

Why Scope?

  • By default coroutines don’t help us to keep track of them, or keep track of any work that’s being done by them
  • If we don’t manage coroutines very carefully, there will be coroutine leaks in the memory
  • Luckily we have to, we must start all the coroutines within a scope
  • Using properties belong to scope we can easily keep track of coroutines, cancel coroutines, handle errors or exceptions thrown by the coroutines
  • This coroutineScope is the interface we have used to provide scope to our coroutine
  • We also have other scopes like GlobalScope to launch top level coroutines

Context of Scope?

  • We can use Dispatchers, and explicit Job instance for context

Here we have only used Dispatcher as context, we can use Job instance like this:- Dispatchers.IO + job

Dispatchers

  • Dispatchers describes the kind of thread where the coroutine should be run
  • We have mainly three Dispatchers — Dispatchers.Main, Dispatchers.IO, Dispatchers.Default
  • Main -> Launch coroutine in Main Thread/ UI Thread
  • IO -> Launch coroutine in a Background Thread
  • Default -> For CPU Intensive tasks

Coroutine Builder

  • This launch is the coroutine Builder
  • Coroutine builders are the extension functions of coroutine scopes which are used to launch coroutines
  • Four main Coroutine Builders -> launch, async, produce, and runBlocking

Launch builder launches a new coroutine without blocking the current thread, Returns an instance of Job which can be used as a reference to coroutine.We use this builder that doesn’t have any result as return value

If we want to get result as return value we should use Async builder, It also allows use to launch coroutine in Parallel. It returns an instance of Deferred<T>.We need to invoke await() to get the value

Switch Coroutine between Threads

  • withContext() is a suspend function
  • As you all know We can’t call any UI component from Background thread, So coroutines has the easiest way to switch between threads i.e with the help of withContext()
withContext(Dispatchers.Main){
// write anything here
}

Suspending functions

  • In Kotlin Coroutines, Whenever a coroutine is suspended, the current stack frame of the function is copied and saved in the memory.
  • When the function resumes after completing its task, the stack frame is copied back from where it was saved and starts running again
  • There are many suspending functions provided by coroutines for making our work easier

Suspending Functions → withContext(), withTimeout(), join(), delay(), await(), coroutineScope, supervisorScope

  • Remember:- If we’re ever going to call those suspending functions from our functions then we must mark our functions with suspended modifier
  • In Above example you can see we have called withContext() function which is a suspending function, from our own function and that’s why we have marked our function with suspend modifier

A suspending function can be called from a coroutine block or suspending function only, not from a normal function

Async and Await

  • Async and Launch is the coroutine builder, Launch coroutine builder returns a job but async coroutine builder returns an instance of Deferred.
  • We can use that Deferred value by invoking its await function
CoroutineScope(Main){
val stock1 = async(IO){
getStock1() // Api Call
}
val stock2 = async(IO){
getStock2() // Api Call
}
val total = stock1.await() + stock2.await()
Log.i(“total”, total)
}
  • This is how we use async and await to get data from different data sources parallel and combined the result

Boooooooom! 🤩 Coroutine is Done ✅

But I’ve seen lots of developers not taking proper advantage of Coroutines or not using Best Recommended Practices, So No Worries at all….

I’m gonna cover those best and important concepts in Coroutines so you can take full Advantage of Coroutines. Here we go!😃

coroutineScope

  • Notice this small ‘c’ here, This is not CoroutineScope with capital ‘C’
  • CoroutineScope is Interface and coroutineScope is a suspending function which allows us to create a child scope within a coroutine scope
  • This coroutine scope guarantees the completion of task when suspending function returns — (we could use async await also)
  • It guarantees the completion of all tasks within the child scope provided by it before the return of the function
  • This is the Recommended best practices. When you have more than one coroutine, you should always start with Dispatchers.Main, and launch with the CoroutineScope interface and Inside suspending functions you should use coroutineScope function which starts with simple ‘c’ to provide a child scope

ViewModelScope

  • In android just before the clearing, viewmodel invokes it’s onCleared() method.
  • Some of the coroutines we launch in a viewmodel has a potential to run even after the viewmodel is cleared from the memory. It might will run until our app is terminated.
  • If that’s not the intention app will end up leaking memory. To avoid that we need to cancel the coroutine within the onCleared function
  • In order to cancel the coroutines started in this scope, we need to pass a Job instance for context of coroutine scope:-
private val myJob = Job()private val myScope = CoroutineScope(Dispatchers.IO + myJob)
  • Manually cancel coroutine:- Myjob.cancel()
  • Canceling coroutines manually might be wasting of time if we have many viewmodels so to avoid those boilerplate code we use viewModelScope.
  • viewModelScope is a CoroutineScope tied to ViewModel lifecycle, It has created to automatically handle cancellation when the ViewModel’s onClear is called

LifecycleScope

  • A LifecycleScope is defined for each lifecycle object. Any Coroutine launched in this scope is cancelled when the lifecycle is destroyed
  • Sometimes we need to create coroutines in objects with a lifecycle, such as activites and fragments. This new scope has specially created for those scenarios. So if coroutine is in the activity, that will be cancelled when onDestroy() method of the activity invoked i.e. we don’t have to manually create job instance, add job instance to scope context, override destroy method and clear coroutines. All these things will be handled
  • If we need to suspend execution of a code block considering the current state of a lifecycle object, For that we have three additional builders

lifecycleScope.launchWhenCreated, lifecycleScope.launchWhenStarted, lifecycleScope.launchWhenResumed

LiveDataBuilder

  • Android architecture component team introduced a new coroutine building block for livedata, This block will automatically become active when the livedata becomes active
  • It automatically decide when to stop executing and cancel the coroutines inside the building block considering the state of the lifecycle owner.
  • Inside the livedata building block, you can use emit() function to set a value to the live data.
  • We just need to observe this users livedata in activity/fragment that’s it. No need to call getUsers() function explicitly

That’s It For Now. 🤘

Also Here’s the Article I Recommend to Study ->

JUnit Testing in Android with Kotlin

Android Apps Best Practices

Subscribe to My Youtube Channel for more such Videos! 🤩

Understand Coroutines by CodingWithPuneet

Happy Coding! Do Clap, Share if you like it and follow me for the updates.

Add me on Linkedin and Twitter

Stay tuned for next Interesting Topic!

--

--

Puneet Grover

Android Team Lead (Senior Consultant) @Deloitte USI | Google Certified Android Dev | Java | Kotlin | Blogger | Sometimes Youtuber