Coroutine & Retrofit. Working with Coroutine and Retrofit and…
By: Nandish Swarup
Tags: Coroutine, Android, Asynchronous, Retrofit

Coroutine & Retrofit

Photo by ThisIsEngineering from Pexels

One can think of a coroutine as a lightweight thread. Like threads, coroutines can run 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. Threads, on the other hand, are expensive to start and keep around.

Coroutines can be considered as a replacement to AsyncTask for tasks that you want to perform in the background and want your app to be responsive at the same time. No more managing thread on your own. Coroutine provides a very easy way to take the burden off your main thread and return the result to the Main thread once the task is completed.

Why do we need Coroutine?

It helps you manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive

NOTE - Coroutines is recommended solution for asynchronous programming on Android

Features of Coroutine

Lightweight: You can run many coroutines on a single thread due to support for suspension, which doesn’t block the thread where the coroutine is running. Suspending saves memory over blocking while supporting many concurrent operations.

Fewer memory leaks: Use structured concurrency to run operations within a scope.

Built-in cancellation support: Cancellation is propagated automatically through the running coroutine hierarchy.

Breaking down coroutine builders:

launch — This builder simply launches a new coroutine and returns a reference to it as a Job object which does not have a result. If you want to block the current thread, instead of launch you may use runBlocking builder instead.

— This builder simply launches a new coroutine and returns a reference to it as a object which does not have a result. If you want to block the current thread, instead of launch you may use builder instead. async — This builder launches new coroutine and returns a reference to it as a Deferred type object which may have a result. It is usually used along with await which is a suspending function which can wait for a result without blocking the current thread.

And Dispatchers.Main — this isn’t a coroutine builder however we pass it into our launch builder in order to notify the Android system that we will need to update the UI thread at some point during our coroutine execution.

Types of Dispatchers

There are majorly 4 types of Dispatchers.

Main Dispatcher IO Dispatcher Default Dispatcher Unconfined Dispatcher

Main Dispatcher:

It starts the coroutine in the main thread. It is mostly used when we need to perform the UI operations within the coroutine, as UI can only be changed from the main thread(also called the UI thread).

IO Dispatcher:

It starts the coroutine in the IO thread, it is used to perform all the data operations such as networking, reading, or writing from the database, reading, or writing to the files eg: Fetching data from the database is an IO operation, which is done on the IO thread.

Default Dispatcher:

It starts the coroutine in the Default Thread. We should choose this when we are planning to do Complex and long-running calculations, which can block the main thread and freeze the UI eg: Suppose we need to do the 10,000 calculations and we are doing all these calculations on the UI thread ie main thread, and if we wait for the result or 10,000 calculations, till that time our main thread would be blocked, and our UI will be frozen, leading to poor user experience. So in this case we need to use the Default Thread. The default dispatcher that is used when coroutines are launched in GlobalScope is represented by Dispatchers. Default uses a shared background pool of threads, so launch(Dispatchers.Default) { … } uses the same dispatcher as GlobalScope.launch { … }.

Unconfined Dispatcher:

As the name suggests unconfined dispatcher is not confined to any specific thread. It executes the initial continuation of a coroutine in the current call-frame and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without mandating any specific threading policy. Or in simpler language, an unconfined dispatcher starts a coroutine in the caller thread, but only until the first suspension point. After suspension, it resumes the coroutine in the thread that is fully determined by the suspending function that was invoked.

The unconfined dispatcher is appropriate for coroutines that neither consume CPU time nor update any shared data (like UI) confined to a specific thread.

Difference Between Dispatcher.IO & Dispatcher.Default

The difference is that Dispatcher. Default is limited to the number of CPU cores with a minimum of 2 and maxes up to N where N is the number of CPU cores present. Hence at a time, only N tasks can run in parallel.

On the IO dispatcher, there are by default 64 threads, so there could be up to 64 parallel tasks running on that dispatcher.

The idea is that the IO dispatcher spends a lot of time waiting (IO blocked), while the Default dispatcher is intended for CPU-intensive tasks, where there is little or no sleep.