Coroutines - Introduction and Implementation
Long operations like internet connection, file upload, download, loading image, database queries, ecc. We can't use long running operation in our Main Thread otherwise it will block the Main Thread and freeze the Application.
So we have background threads to perform those long running operations.
But there is a limit of creating thread. Because it will run Out Of Memory if you create more and more threads and the app will crash with exception.
Coroutines are basically the core mechanism that we're using to handle long running and asynchronous code. Any code involving switching threads or using coroutines has some asynchronous aspects. Ex. When you click a button, handling of the button click is happening asynchronously in parallel with the UI updating.
Synchronous Code (running code in series) : TaskA -> TaskB -> TaskC
Asynchronous Code (running code in parallel) : Task timing is not dependent on each other
TaskA -------------->
------------TaskB....>
---TaskC------------>
We have one background thread and launch as many coroutines as you want. The memory consumption is of 1 background thread so no problem of Out of Memory Exception.
Coroutines Facts:
- Light-weight threads
- Run in parallel, wait, communicate with each-other.
- Coroutine!= Threads
- We can create thousands of them without any Memory Issue.
Implementation
build.gradle(Module)
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines"version_kotlin_coroutines = "1.3.9"
Global scope is used to launch top-level coroutines which are operating on the whole application lifetime and are not cancelled prematurely.
It is a singleton scope that returns a completely empty
coroutineContext
. Since there's no Job
associated with it, you cannot cancel it, so its lifecycle is basically "forever". So it is usually discouraged to use GlobalScope. CoroutineScope
It controls the lifetime of the coroutine. When you cancel scope, all the coroutines that was running in that scope also gets canceled.
Since it's fairly common to start long-running work from a ViewModel, you'll often find yourself creating and running coroutines from inside ViewModels.
Normally, you need to create and configure a new coroutine scope manually for each view model that you wanted to run a coroutine in.
class MyViewModel : ViewModel() {
private val viewModelJob = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.Main + viewModelJob)
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
fun launchDataLoad(){
scope.launch { longRuningTask() // suspend function } }
suspend fun longRuningTask(){
}
}
That's a lil bit of boilerplate so to avoid that we can use the lifecycle ViewModel kit X library which provides an extension function called ViewModelScope.
Instead we can use the ViewModelScope extension inside of a view model.
ViewModelScope
It provides a coroutine scope associated with each view model that is configured and managed automatically for you.
Here are two important aspects of ViewModelScope default behaviour.
fun launchDataLoad_ViewModelScope(){
viewModelScope.launch { longRuningTask()
}}
ViewModelScope
It provides a coroutine scope associated with each view model that is configured and managed automatically for you.
Here are two important aspects of ViewModelScope default behaviour.
- The ViewModel scope is tied to the ViewModel such that when the ViewModel is cleaned up, basically when the onCleared() is called, the scope is automatically canceled. This ensures that when your ViewModel goes away so does all of that coroutine work that you started in the ViewModel. This helps you avoid wasted work and memory leaks.
- Second, the scope uses the Dispatchers.Main and coroutine dispatcher. As mentioned, a coroutine dispatcher controls what thread the coroutine code runs on. Dispatchers.Main is the standard dispatcher that puts the coroutine on the UI or main thread. Now, this make sends as a default for ViewModel coroutines because often ViewModels manipulate the UI.
It creates a coroutine that blocks the current thread on which it is executed.
What are suspending function ?
- The suspending function are only allowed to call from another suspending function or inside a coroutine.
- It has a suspend modifier
- eg. delay(1000) function : will wait 1000 milliseconds
withContext()
Since withContext is a suspend call, that is it won’t go to the next line until it finished. Since withContext is a suspend call and does not block the main thread, we can do other tasks while the IO thread is busy in executing the function.
Dispatchers
Kotlin coroutines use dispatchers to determine which threads are used for coroutine execution.
Comments
Post a Comment