Coroutines: Replacement of AsyncTask Class in Android

Dr. Vipin Kumar
5 min readMay 19, 2021

What is Coroutines?

Coroutines = Co + Routines

  • Here, Co means cooperation and Routines means functions.
  • It means that when functions cooperate with each other is called Coroutines.
  • Coroutines make writing asynchronous and non-blocking code easy to read and understand by eliminating the need to handle traditional callback pattern.
  • It working is conceptually similar to a thread that it takes a block of code to run that works concurrently with the rest of the code. However, a coroutine is not bound to any particular thread. It may suspend its execution in one thread and resume in another one.
  • Coroutines can be thought of as light-weight threads, but not thread.
  • Coroutines is our recommended solution for asynchronous programming on Android, because AsyncTask class is deprecated in Android with Kotlin Programming now.
Coroutines

Coroutines Features

  • Lightweight
  • Built-in cancellation support
  • Fewer memory leaks
  • Jetpack integration

Types of Coroutines

There are two type so Coroutines

  • Stackless: don’t have own stack
  • Stackful: have own stack

Kotlin implements stackless Coroutines

Coroutines vs Thread

  • Coroutines executes within a thread or execute threads
  • Coroutines are suspendable
  • They can switch their context (Thread Switching)
  • Coroutine is as a light-weight thread. Run like threads in parallel, wait for each other and communicate.
  • The biggest difference is that Coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance.
  • But true threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine.

Coroutines Components

  • Suspend Functions
  • Coroutine Context
  • Coroutine Scope
  • Dispatchers
  • Coroutine Builders: 1. Launch, 2. Async, 3. runBlocking
  • Job

Suspend Functions

  • A suspend function is simply a function that can be paused and resumed at a later time. They can execute a long running operation and wait for it to complete without blocking.
  • The syntax of a suspend function is similar to that of a regular function except for the addition of the suspend keyword. It can take a parameter and have a return type.

suspend fun backgroundTask(param: Int): Int {

// long running operation

}

  • Suspend functions can only be invoked by another suspend function or within a coroutine.

Coroutine Context

  • CoroutineContext is the execution environment to run/execute Coroutine code asyncronously.
  • Every coroutine in Kotlin has a context that is represented by an instance of CoroutineContext interface.
  • A context is a set of elements and current coroutine context is available via coroutineContext property:

fun main() = runBlocking<Unit> {

println(“My context is: $coroutineContext”)

}

  • The context determines on which thread the Coroutines will run like Default, Main, IO, and Unconfined

Coroutine Scope

  • CoroutineScope is the interface that define the concept of Scope with Coroutines, to execute a coroutine you need a scope.
  • CoroutineScope use Dispatchers to decide Coroutines scope.

Coroutines Dispatchers

  • Dispatchers specify in which scope coroutine will work.
  • There are 4 dispatchers
  1. Default: It is recommended to use CPU intensive works such as very costly mathematical computations.
  2. IO: It is recommended to used IO Intensive works such as Network Call, File IO or socket IO
  3. Main: It is recommended to use Main thread operations such as updating UI.
  4. Unconfined: It is not confined for any use-case. It is recommend to use Testing purpose.

Coroutine Builders

  • Coroutine builders are functions that help to create a coroutine. They can be called from normal functions because they do not suspend themselves.
  • Three coroutine builders are listed below.
  1. launch: start a coroutine in the background and keep working.
  2. async: allows to perform an asynchronous task which return a value
  3. runBlocking: this blocks the current thread and waits for the coroutine to finish execution.

Launch Builder Example

fun main() {

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

delay(1000L)

println(“World!”)

}

println(“Hello,”) // main thread continues here immediately

runBlocking { // but this expression blocks the main thread

delay(2000L) // … while we delay for 2 seconds to keep JVM alive

}

}

Async Builder Example

fun main() {

val deferredResult: Deferred<String> = GlobalScope.async {

delay(1000L)

“World!”

}

runBlocking {

println(“Hello, ${deferredResult.await()}”)

}

}

runBlocking Builder Example

fun main() {

println(“Hello,”)

// we create a coroutine running the provided suspending lambda

// and block the main thread while waiting for the coroutine to finish its execution

runBlocking {

// now we are inside a coroutine

delay(2000L) // suspends the current coroutine for 2 seconds

} // will be executed after 2 seconds

println(“World!”)

}

Job in Coroutines

  • A Job is a cancellable thing with a life-cycle that culminates in its completion. Coroutine job is created with launch coroutine builder. It runs a specified block of code and completes on completion of this block.
  • Job control Coroutines using following functions that are available on the Job interface.
  1. start(): start Coroutines
  2. join(): hold Coroutines until it finish task
  3. cancel(): cancel Coroutines

Job Example

val job = GlobalScope.launch(Dispatchers.Default) {

repeat(5)

{

Log.d(TAG, “Coroutines is still working”)

// delay the coroutine by 1sec

delay(1000)

} }

runBlocking {

// waiting for the coroutine to finish it’s work

job.join()

Log.d(TAG, “Main Thread is Running”)

}}

Normal Operations for Main Thread

In Android, Main thread is only capable to run normal operations like UI Interaction, Button Click, and etc

Normal Operation by Main Thread

Heavy Operations for Main Thread

  • In Android, if we try to run heavy operations as shown in image, Produce ANR (Application Not Responding) Error
Heavy Operation by Main Thread

Solution 1: Threads to Overcome ANR problems

  • Better solution but occupied more recourses as compare to Coroutines
Threads by Main Thread

Solution 2: Coroutines to overcome ANR problems

  • Optimum Solution, better than threads, occupied less resources
Coroutines by Main Thread

Practical Example in Android Studio:

Loading Image in Image View by Internet on Clicking on Button

Adding Dependence in Module Level Gradle

dependencies {

implementation ‘org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9’

}

Layout Design

Layout before clicking on Load Image Button

Before Clicking on Load Image Button

Layout After Clicking on Load Image Button

After Clicking on Load Image Button

Main Activity Code

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

binding= ActivityMainBinding.inflate(layoutInflater)

setContentView(binding.root)

binding.btnImageLoad.setOnClickListener(View.OnClickListener {

getImageByCoroutines()

})

}

private fun getImageByCoroutines()

{

GlobalScope.launch(Dispatchers.IO) {

val urlImage= URL(“https://i.ytimg.com/vi/D6Lbs8ln49s/maxresdefault.jpg")

val httpURLConnection=urlImage.openConnection() as HttpURLConnection

httpURLConnection.connect()

val bitmap=BitmapFactory.decodeStream(httpURLConnection.inputStream)

launch (Dispatchers.Main){

binding.imageView.setImageBitmap(bitmap)

}

}

}

}

--

--

Dr. Vipin Kumar

Assoc. Prof. , DCA & Assoc. Head (SD), SDFS, at KIET, PhD (CS) My YouTube Channel: Dr. Vipin Classes (https://www.youtube.com/channel/UC-77P2ONqHrW7h5r6MAqgSQ)