Top 10 Android Kotlin Coroutines Interview Questions (2024)

Kotlin Coroutines is a concurrency design pattern introduced in Kotlin by JetBrains. It provides a way to write asynchronous coding that looks and behaves like synchronous coding, using the concept of Suspend Functions.

In this blog, we will explore Top 10 important Android Kotlin Coroutines Interview Questions with Example in 2024 and provide code snippets to illustrate their usage in Kotlin Android.


Android Kotlin Coroutines Interview Questions in 2024

Top 10 Important Android Kotlin Coroutines Interview Questions in 2024 with proper examples.

Ques-1: What is coroutines and How coroutines better than thread?

Ans-1: Coroutines is a concurrency design pattern introduced in Kotlin by JetBrains. It provides a way to write asynchronous coding that looks and behaves like synchronous coding, with the help of suspend functions.
A coroutine is a concurrency design pattern that you can use to simplify the code and executes task asynchronously. It’s a lightweight that doesn’t require the overhead of context switching. In the world of Kotlin, a coroutine is a piece of code that can be suspend and resume task without blocking the main thread.

Why do we need Kotlin Coroutines?
  • Simplified Asynchronous Code: Coroutines provide a structured way to manage concurrency pattern, making it easier to handle complex asynchronous task. They allow developers to write sequential or structured looking code while still achieving concurrency pattern.

  • Lightweight: Coroutines are very lightweight compared than threads. You can launch thousands of task in coroutines, and they won’t bring your system to a halt.

  • Suspend and Resume: Coroutines allow for suspend and resume execution at any specific points, making it easier to handle long-running operations without blocking the main thread. This helps in keeping the UI part responsive and improves the user experience.

  • Exception Handling: Coroutines provide in-built exception handling features, making it easier to handle and propagate exceptions within the coroutine context.

  • Unlike threads for coroutines: the application by default does not wait for it to finish the task.

Let’s take a example of using coroutines in Kotlin Android:

import kotlinx.coroutines.*

fun performTask() {
GlobalScope.launch {
// Perform time-consuming task here
// This code will run in a coroutine
}
}


Ques-2: What is Coroutines Dispatchers and Types of Coroutines Dispatchers?

Ans-2: A Kotlin coroutine dispatcher is an essential functionality provided by Kotlin coroutines. It helps us to conclude which coroutine will run on which thread from a pool of threads. 
Dispatchers help coroutines to deciding on which type of work has to be fit for particular thread.

There are majorly 4 types of Dispatchers.
  • Main  Dispatcher
  • IO Dispatcher
  • Default Dispatcher
  • Unconfined Dispatcher
Main Dispatcher:
It is used to perform all the UI Operation within this coroutine dispatcher, as UI can only be changed from the main thread.
It starts this coroutine dispatcher in the main thread only. 

Main Dispatcher Example:

GlobalScope.launch(Dispatchers.Main) {
              // our coroutine has been launched
       }


IO Dispatcher:
It starts this coroutine dispatcher in the IO thread only, it is used to perform all the data operations such as like networking, reading or writing to the files, and reading or writing from the database. these all performed on the IO thread.

IO Dispatcher Example:

GlobalScope.launch(Dispatchers.IO) {
              // our coroutine has been launched
       }


Default Dispatcher:
It starts this coroutine dispatcher in the Default Thread only. We should choose this when we are planning to do Complex and long-running calculations.
Eg: Suppose we need to do the 10,000 calculations and we are doing all these calculations on the main thread, and if we wait for the result of 10,000 calculations, till that time our main thread would be blocked and freeze the UI, leading to bad user experience. So in this case we need to use the Default Thread. 

Default Dispatcher Example:

GlobalScope.launch(Dispatchers.Default) {
              // our coroutine has been launched
       }


Unconfined Dispatcher:
Unconfined dispatcher is not confined to any other specific thread. It's implement 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 suspend function, without mandating any specific threading policy. 

GlobalScope.launch(Dispatchers.Unconfined) {
              // our coroutine has been launched
       }

Ques-3: Why coroutines is lighter than thread?

Ans-3: You can run many coroutines task on a single thread due to support for suspend function, which doesn't block the main thread where the coroutine is running.
Suspend function saves memory over blocking while supporting many concurrent task.
After using coroutines having fewer memory leaks.
Use structured concurrency to run multiple task within a coroutine scope.

Ques-4: What is coroutine builder and type of coroutine builder?

Ans-4: There are mainly two functions in Kotlin to start the coroutines. 
  • launch
  • async
launch:
The launch is basically fire and forget.
launch is used when you don’t need a result back after execution.
launch will not block your main thread.
launch can't be used when you need the parallel execution of networking calls.

Eg. It is used for updating UI part independently, making network request or performing database operations (like read and write data) in the background.

launch Real Time Example:

fun launchFn()
{
  var resultOne = "Android"
  var resultTwo = "Kotlin"
  Log.i("Launch", "Before")
  launch(Dispatchers.IO) { resultOne = function1() }
  launch(Dispatchers.IO) { resultTwo = function2() }
  Log.i("Launch", "After")
  val resultText = resultOne + resultTwo
  Log.i("Launch", resultText)
}
 
suspend fun function1(): String
{
  delay(1000L)
  val message = "function1"
  Log.i("Launch", message)
  return message
}
 
suspend fun function2(): String
{
  delay(100L)
  val message = "function2"
  Log.i("Launch", message)
  return message
}

launch final output of above code snippet:
Launch: Before
Launch: After
Launch: AndroidKotlin //don't wait for the results, as it is non blocking the main thread.
Launch: function2
Launch: function1

async:
async, which has an await() function returns the result of the coroutine. 
async function is used when you need a result back after execution.
async will block the main thread because await function is used at the entry point.
Use async function only when you need the parallel execution of networking calls.

Eg. when we want to fetch multiple users data from the database by using multiple parallel network calls and then use them for computing some results based on their data. 

async Real Time Example:

fun asyncFn()
{
  Log.i("Async", "Before")
  val resultOne = Async(Dispatchers.IO) { function1() }
  val resultTwo = Async(Dispatchers.IO) { function2() }
  Log.i("Async", "After")
  val resultText = resultOne.await() + resultTwo.await()
  Log.i("Async", resultText)
}
 
suspend fun function1(): String
{
  delay(1000L)
  val message = "function1"
  Log.i("Async", message)
  return message
}
 
suspend fun function2(): String
{
  delay(100L)
  val message = "function2"
  Log.i("Async", message)
  return message
}

async final output of above code snippet:
Async: Before
Async: After
Async: function2 
Async: function1
Async: function1function2 //as main thread get blocked due to await(), it is printed at the end bcz. await() function

Ques-5: What is the suspend function in Kotlin Coroutines?

Ans-5: Suspend functions is a functions that could be started, paused and resumed without blocking a main thread. It is only allowed to be called from other suspend functions or coroutine function.

A suspend functions is a function that can be paused and resumed at a later time. They can execute a long running task and wait for it to complete the operation without blocking the main thread.

Ques-6: How can you handle errors in Kotlin Coroutines?

Ans-6: In Kotlin Coroutines, we can handle exceptions using try/catch blocks.
Additionally, the Coroutines provides a features of CoroutineExceptionHandler interface can be used to define a global handler for uncaught exceptions within a coroutine scope.

First try/catch exception example:
    fun main(): Unit = runBlocking {
    try {
        coroutineScope {
            launch {
                delay(1000)
                throw Error("Some error")
            }
            launch {
                delay(2000)
                println("Will be printed")
            }
            launch {
                delay(2000)
                println("Will be printed")
            }
        }
    } catch (e: Throwable) {
        println("Caught $e")
    }
    println("Done")
}
// (1 sec)
// Caught java.lang.Error: Some error
// Done

Second CoroutineExceptionHandler exception example:
fun main(): Unit = runBlocking {
  val handler =
      CoroutineExceptionHandler { ctx, exception ->
          println("Caught $exception")
      }
  val scope = CoroutineScope(SupervisorJob() + handler)
  scope.launch {
      delay(1000)
      throw Error("Some error")
  }

  scope.launch {
      delay(2000)
      println("Will be printed")
  }

  delay(3000)
}
// Caught java.lang.Error: Some error
// Will be printed
    

Ques-7: What is CoroutineScope and Types of CoroutineScope?

Ans-7: CoroutineScope is defined the scope of a coroutine. It provides a structured way to launch coroutines and ensures that they are automatic cancelled when the scope is cancelled.

There are basically 3 scopes in Kotlin coroutines:
  • Global Scope
  • LifeCycle Scope
  • ViewModel Scope
Global Scope:
When Coroutines are launched within the global scope, they live long as the application exist. If the coroutines finish it’s a job, it will be not destroyed and keep alive until the application dies.
We usually use this scope when we want to launch a long running operation on application scope so that the task will remains alive until the application killed.

Global Scope example:

GlobalScope.launch(Dispatchers.Main) {
  println("loading..")
  delay(3000)
  println("job is done")
}   

LifeCycle Scope:
When we use the lifecycle scope, all the coroutines launched within the activity scope. they live long as the activity exist, coroutine dies when the activity dies. It is beneficial as our coroutine will not keep running even after activity destroyed. Its also prevent the memory leaks.

LifeCycle Scope example:

lifecycleScope.launchWhenResumed {
  println("loading..")
  delay(3000)
  println("job is done")
}


ViewModel Scope:
ViewModel scope is same as the lifecycle scope, only difference is that the coroutine in this scope will live long as the view model is alive.Without ViewModelScope usually we want to cancel the coroutine on clear state. But using this ViewModelScope we don’t need to cancel coroutine manually, ViewModelScope is depend on ViewModel its cancel automatically if the ViewModel is destroyed.

ViewModel Scope example:

viewModelScope.launch {
  println("loading..")
  delay(3000)
  println("job is done")
}

Ques-8: What is withContext and How can we use the withContext function in Kotlin Coroutines?

Ans-8: withContext is a function used to switch context within a coroutine. It suspends the current coroutine, switches to the specified context, and resumes execution in the new context. 

WithContext example:

 fun startWithContextTask() 
{
 CoroutineScope.launch(Dispatchers.Main)  {
    val resultOne = withContext(Dispatchers.IO) { TaskOne() }
    val resultTwo = withContext(Dispatchers.IO) { TaskTwo() }
    val combinedResult = resultOne + resultTwo
  }
}


Ques-9: How can we achieve parallelism using Kotlin Coroutines?

Ans-9: Parallelism in coroutines can be achieved using the async builder along with await function to await the results. Multiple asynchronous operation can be started concurrently, and their results can be combined when its needed.

Parallelism using Kotlin Coroutines Example:

import kotlinx.coroutines.*

suspend fun sendDataAndAwaitAcknowledge() = coroutineScope {
    awaitAll(async {
        awaitAcknowledge()
    }, async {
        sendData()
    })
}

fun sendData() = true

fun awaitAcknowledge() = false

fun main() {
    runBlocking {
        println(sendDataAndAwaitAcknowledge()) // [false, true]
    }
}


Ques-10: Explain the difference between launch and runBlocking in Kotlin Coroutines.

Ans-10: 
launch is a coroutine builder used to start a new coroutine task asynchronously and its non blocking in nature, allowing it to run concurrently with other coroutines.

launch Example:

GlobalScope.launch(Dispatchers.Main) {
            delay(3000)
            Log.d(TAG,"User is in the Global Scope ")
}

runBlocking is a coroutine builder that blocks the current thread until the task inside it completed. It’s mainly used for testing purpose or adapting synchronous to the asynchronous code behaviour.

runBlocking Example:

runBlocking {
              delay(5000)
              Log.d(TAG,"start of the run-blocking")
              Log.d(TAG,"End of the runBlocking")
}


Reference Site

here you can learn more about Kotlin Coroutines Interview Questions

Conclusion 

In this post i have provided you Top 10 important Android Kotlin Coroutines Interview Questions in 2024 with proper examples. you can easily learn and prepare yourself for the interview.
Oversimplified Coding

I am Shubhangam Upadhyay founder of Oversimplified Coding. My motive of this blog to help those developer are just start there carrier in coding line. We cover here Android, Kotlin, Core Java, Jetpack Compose and Flutter etc. related topics. I have 6+ Years of experience in Android Development and working on MNC company as a Senior Android Developer Position. I have worked on 5 different companies and experience on many different type of real time application project.

*

Post a Comment (0)
Previous Post Next Post