Handling “What are Kotlin Coroutines?” Interview question

Hitesh Kohli
6 min readOct 6, 2023

--

Photo by Tran Mau Tri Tam ✪ on Unsplash

Introduction

You must have used Network calls in your app.

Have you ever wondered what will happen if a network call takes time to load?

The UI of our app will freeze due to delayed responses from network calls.

The solution to the UI freezing is concurrency. If we call the network requests with the help of coroutines, they will not run on the UI thread. Thus, it will give a smoother experience to the user.

If you do not understand it yet, it’s okay. We will go deeply into coroutines.

Before we start exploring Android. I have something for you. It's free and most importantly it's for all Android developers.

A newsletter that is written by Android Developers for Android Developers.

What can you expect from us:

→ Apps in the news
→ Android Interview Question
→ Interesting Facts about Apps
→ Coding Memes
→ Core Concept
→ Advice Block From Expert
→ Interesting Twitter Thread

Basics

The CPU of our mobile does not execute multiple functions in parallel. A function starts executing and then pauses, and then another function is executed. It happens so seamlessly that it appears parallel to the user.

What will happen if a function does not stop or runs for too long?

It will lead to complete usage of memory or CPU, leading to crashing of the application.

Therefore, to execute a long-running function, we needed a different approach.

Photo by Christian Wiediger on Unsplash

We know that the CPU runs multiple threads. To solve the crashing problem, the function is executed on a different thread than the UI thread. Only UI-related tasks need to run on the UI thread, avoiding the application crash.

But, there is one more problem. Threads are also costly to run. Therefore, we need a more lightweight method that solves our problem of executing multiple functions in parallel.

Here is where the Kotlin Coroutines shines.

Welcome to Kotlin Coroutines

If we want to call a Load Intensive task with our code, it can lead to the blocking of our user interface. Therefore, we need to use different threads to keep the user experience pleasant. An example of a load-intensive task can be a network call. If we do a network call from our main thread from an API. We have to wait for the response before we can execute further functions. If takes more than a few seconds, our app will freeze or crash. Therefore, we need to do network calls on a different thread. But, utilising threads can be costly as they require shifting of CPU resources.

Photo by Rami Al-zayat on Unsplash

So what are other methods that we can use for this purpose?
- Callbacks
- Coroutines

Callbacks:

Callbacks can be good, but if we are doing multiple calls. It will lead to call-back hell. Hence coroutines.

Kotlin Coroutines:

Coroutines are lightweight threads that work on top of actual threads. They are stackless, so they do not map to actual threads, but instead work like a framework. Therefore we can deploy thousands of them without any CPU cost. In the case of actual threads, they utilize CPU resources and therefore aren’t used for concurrency. Light weight nature of coroutines also comes from their stackless nature.

Let’s Break down Parts of Coroutines:

- Threads
- With Context
- Scope
- Launch
- Async and Await
- Dispatchers
- Suspend Functions

Photo by Rob Hampson on Unsplash

Threads -

Threads can be of three types:
- IO — Used for Disk or Network Applications
- Main — Used for updating UI
- Default — Used for CPU-intensive Applications

WithContext -

WithContext is used to shift a suspend function to a particular Thread. It does not create a new coroutine. So its only task is to shift the suspended functions. Withcontext is also suspended in nature and therefore can only be called in the coroutine scope.

Scope -

It defines the scope of the coroutine.
The scope can be of many types:
- GlobalScope
- ViewModelScope
- LifecycleScope
- CoroutineScope
The main function of the scope is to define the lifetime of the coroutines. As soon as the scope gets finished so does the coroutine.

Why do we need scopes?

Scopes define the lifetime of a coroutine. If we want a coroutine to last the lifecycle of an activity. We can use LifeCycleScope to call the suspend functions As soon as the activity is closed the coroutine also finishes. In the case we call GlobalScope, the coroutine can last even if the activity is closed and leads to memory leakage. Therefore it is advisable to use scopes like ViewModel scope or lifecycle scope.

Launch -

The launch is used to start the coroutines. The launch is a fire-and-forget type of starting, where we are not expecting any returning output. It simply means that it does not wait for any response from the coroutine.

Async and Await -

Async and Await are also used to start the coroutines. They are used to start and wait for the response from our coroutines.

Dispatchers -

Dispatchers are used to decide the thread of the coroutines.
- Dispatchers. IO
- Dispatchers. Main
- Dispatchers. Default

Suspended Functions-

Suspended Functions are the functions that can be stopped and restarted again. These functions can only be called in coroutine scope.

Photo by Gilles Lambert on Unsplash

Why and How do we do Exception Handling in Coroutines?

In case we are using coroutines with network responses and the response returns a null.

It could lead to the crashing of the application therefore we use exceptional handling.

Both launch and async are handled differently.

Exception Handling in case of launch function:

- Using Try and catch
- Using Handlers

We can use try-and-catch functions to catch any kind of exception if the response results in a null.

In the case of handlers, we use:
-> CoroutineExceptionHandlers

Exception Handling in the case of async and await:

- Using Coroutinescope
- Using Supervisor Scope

Coroutinescope is used to launch multiple async and await suspended functions. An advantage of coroutinescope is that the app would not crash even if its network response returns null. But, we can not return an empty response in the case of coroutine scope.

Supervisorscope is used in case we want to return an empty response even if a network response returns null.

Photo by NordWood Themes on Unsplash

What are Dispatchers?

- Dispatchers are used to decide on which thread to
execute the suspended functions. It shifts the suspended function to a particular thread that is most suitable for the task. The thread is decided based on the type of the workload.

Dispatcher Types:

1 — Main — Used for Updating UI or low-level tasks

2 — IO — Used for Disk related or network-related tasks

3 — Default — Used for CPU Intensive Tasks

4 — Unconfined — Suspended functions will execute on a given thread and will continue executing on whatever thread available if stopped.

Unconfined Dispatchers aren’t used much. They are used in cases where you do not care about executing any suspended functions.

This is all for today. We will keep on exploring more and I will bring part 2 of this blog with more details. Thank You.

If you liked this article. I have something for you. It’s free and most importantly it’s for all Android developers.

A newsletter that is written by Android Developers for Android Developers.

What can you expect from us:

→ Apps in the news
→ Android Interview Question
→ Interesting Facts about Apps
→ Coding Memes
→ Core Concept
→ Advice Block From Expert
→ Interesting Twitter Thread

--

--

Hitesh Kohli

I will help you build distribution with apps |Building and Designing apps| Writing Newsletters 📩| Building @Developcommute & Niwa