Kotlin Coroutines 1
Mohamad Abuzaid 1 year ago
mohamad-abuzaid #kotlin

Kotlin Coroutines (1/3)

What is Coroutines? How do we use it? and What are its main components?

Note: Kotlin Coroutines is a long topic that we will cover in three articles. So, let’s start…

In this article we will cover the following topics in Kotlin Coroutines:

  • What is Kotlin Coroutines?
  • Coroutines Builders.
  • Coroutines Scope.

--------------

[1] What is Kotlin Coroutines?


Coroutines are a feature in Kotlin that allow developers to write asynchronous and non-blocking code in a more readable and concise manner. They allow you to write sequential, blocking-style code that runs asynchronously, and enables you to easily write and manage asynchronous code, such as network requests or database operations, without the need for callbacks or manual thread management.

----------------------

(a) Why use Coroutines?


There are several reasons why you might choose to use coroutines in your Kotlin projects:

  1. Asynchronous Programming: Coroutines allow you to write asynchronous code that runs in the background, without blocking the main thread. This can greatly improve the performance and responsiveness of your applications.
  2. Simplified Thread Management: Coroutines handle thread management for you, making it easier to write concurrent code. You don’t have to worry about creating or managing threads, or dealing with synchronization issues.
  3. Improved Code Readability: With coroutines, you can write asynchronous code that is easy to read and understand, as it looks like sequential, blocking-style code. This makes your code more maintainable and less prone to bugs.
  4. High Performance: Coroutines are designed to be lightweight and efficient, making them well-suited for use in high-performance and low-latency applications.
  5. Composability: Coroutines can be combined and composed, just like any other function in Kotlin. This allows you to write reusable and modular code that is easy to maintain and test.

Overall, coroutines are a powerful tool for writing asynchronous and concurrent code in Kotlin, and they provide many benefits that make your code more readable, maintainable, and performant.


(b) How can we create them?


In Kotlin, you can create coroutines using the suspend keyword and the GlobalScope.launch function.

fun main() {
    GlobalScope.launch {
        // this block of code will run in the background
        delay(1000)
        println("Hello from coroutine")
    }
    println("Hello from main")
    Thread.sleep(2000)
}

In this example, the coroutine is created using the GlobalScope.launch function, which launches the coroutine in a separate background thread. The suspend keyword is used to mark the coroutine as a suspendable function, which means it can be paused and resumed as necessary.

The delay function is a suspension function that waits for the specified amount of time before continuing. In this example, the coroutine waits for 1 second before printing the message “Hello from coroutine”.


(c) What are the suspended functions?


Suspended functions are a key concept in coroutines in Kotlin. A suspended function is a function that can be paused and resumed, allowing other work to be done while it is waiting.

Suspended functions are marked with the suspend keyword, and they can be called only from another coroutine or from a function marked with the suspend keyword.

Suspended functions allow you to write asynchronous code that looks and behaves like blocking code. For example, you can use a suspended function to perform a network request, and the function will be suspended while the request is being processed, allowing other work to be done in the meantime.

suspend fun fetchData(): String {
    delay(1000)
    return "Data fetched"
}

fun main() = runBlocking {
    val data = fetchData()
    println(data)
}

In this example, the fetchData function is marked as a suspended function with the suspend keyword. The function uses the delay function, which is a suspension function that waits for the specified amount of time before continuing. In this case, the function waits for 1 second before returning the string “Data fetched”.

-------------------

[2] Coroutines Builders


Coroutine builders are functions that build and launch coroutines in Kotlin. They provide an easy way to create coroutines and manage their lifecycle.

There are several coroutine builders available in the Kotlin standard library, including:

  1. runBlocking: This function creates a new coroutine and blocks the current thread until the coroutine is complete.
  2. launch: This function launches a coroutine in the selected scope and returns a Job object that can be used to manage the lifecycle of the coroutine.
  3. async: This function creates a new coroutine and returns a Deferred object that can be used to retrieve the result of the coroutine when it is complete.
  4. withContext: This function creates a new coroutine that runs in a specified context, such as a different thread or dispatcher.


(a) runBlocking


runBlocking creates a new coroutine and blocks the current thread until the coroutine is complete. It is typically used for testing or for simple use cases where you want to wait for a coroutine to finish before continuing.

fun main() = runBlocking {
    launch {
        // this block of code will run in the background
        delay(1000)
        println("Hello from coroutine")
    }
    println("Hello from main")
    delay(2000)
}

In this example, the runBlocking function is used to create a coroutine that runs in the current thread. The launch function is used to launch a separate coroutine within the runBlocking coroutine. The delay function is used to pause both the main thread and the coroutine for the specified amount of time.

The main thread prints the message “Hello from main” and then waits for 2 seconds using the delay function. During this time, the coroutine is running in the background and will print the message “Hello from coroutine” after 1 second.

After 2 seconds, the runBlocking coroutine will complete and the program will terminate.


(b) launch


launch launches a coroutine in the selected scope. It returns a Job object that can be used to manage the lifecycle of the coroutine.

fun main() {
    val job = GlobalScope.launch {
        // this block of code will run in the background
        delay(1000)
        println("Hello from coroutine")
    }
    println("Hello from main")
    job.cancel()
}

In this example, the coroutine is created using the GlobalScope.launch function, which launches the coroutine in a separate background thread. The delay function is used to pause the coroutine for 1 second, and the println function is used to print a message.

(c) async


async creates a new coroutine and returns a Deferred object that can be used to retrieve the result of the coroutine when it is complete. The async function is useful for performing asynchronous computations and retrieving the result.

fun main() = runBlocking {
    val result = async {
        // this block of code will run in the background
        delay(1000)
        42
    }
    println("Hello from main")
    println("Result: ${result.await()}")
}

In this example, the async function is used to create a coroutine that performs a computation and returns the result. The runBlocking function is used to create a coroutine that blocks the current thread, and the await function is used to retrieve the result of the async coroutine.

The main thread prints the message “Hello from main” and then retrieves the result of the async coroutine using the result.await() function. This function blocks the current thread until the async coroutine is complete and returns the result, which is the value 42 in this example.


(d) withContext


withContext allows you to switch the context (thread, dispatcher) in which a coroutine runs. It is used to execute a block of code within a specific context and then return to the previous context.

fun main() = runBlocking {
    val result = withContext(Dispatchers.Default) {
        // this block of code will run in the background using the Default dispatcher
        delay(1000)
        42
    }
    println("Hello from main")
    println("Result: $result")
}

In this example, the withContext function is used to switch to the Dispatchers.Default context, which is a dispatcher that provides a default pool of threads for running coroutines. The block of code within the withContext function will run in the background using this dispatcher.

The main thread prints the message “Hello from main” and then retrieves the result of the withContext coroutine. The delay function is used to pause the withContext coroutine for 1 second, and the result of the coroutine is the value 42.

This is a simple example of how to use the withContext function to change the context in which a coroutine runs, and there are many other functions and libraries available for working with coroutines in more complex situations.

------------------

[3] Coroutines Scope


Coroutine Scopes are a way to manage the lifecycle of coroutines and control how they are organized and executed. A scope defines the lifetime of a coroutine and provides a way to cancel or wait for the completion of multiple coroutines.

There are several built-in scopes in Kotlin, including:

  • GlobalScope: This is the root scope for all coroutines and is not tied to any particular lifecycle. It runs coroutines independently of any other coroutines or the lifecycle of the app.
fun main() {
    GlobalScope.launch {
        // this coroutine will run independently of any other coroutines
        println("Hello from GlobalScope")
    }
    println("Hello from main")
    runBlocking { delay(2000L) }
}


  • CoroutineScope: This is a scope that you can create and manage in your code. It’s tied to a specific lifecycle and provides a way to cancel all coroutines associated with that scope when the lifecycle ends.
fun main() = runBlocking {
    val scope = CoroutineScope(Dispatchers.Default)
    scope.launch {
        // this coroutine will be cancelled when the runBlocking coroutine is cancelled
        println("Hello from CoroutineScope")
        delay(1000L)
        println("Goodbye from CoroutineScope")
    }
    println("Hello from main")
    delay(2000L)
    println("Goodbye from main")
}


  • lifecycleScope (Android Only): This is a scope that is tied to a LifecycleOwner such as an Activity or a Fragment. It provides a way to automatically cancel coroutines when the lifecycle of the LifecycleOwner ends.
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycleScope.launch {
            // this coroutine will be cancelled when the activity is destroyed
            println("Hello from lifecycleOwnerScope")
            delay(1000L)
            println("Goodbye from lifecycleOwnerScope")
        }
    }
}


  • viewModelScope (Android Only): This is a scope that is tied to an instance of an Android ViewModel. It provides a way to automatically cancel coroutines when the ViewModel is destroyed.
class MyViewModel : ViewModel() {
    fun doSomething() {
        viewModelScope.launch {
            // this coroutine will be cancelled when the viewModel is destroyed
            println("Hello from viewModelScope")
            delay(1000L)
            println("Goodbye from viewModelScope")
        }
    }
}


That's it for now… We will continue our Coroutines talk in the following two articles.

-------------------


Next Part ==> Kotlin Coroutines (part 2)

1
1.2K
Effective UI/UX Design in Android Apps (1/3)

Effective UI/UX Design in Android Apps (1/3)

1675112374.jpg
Mohamad Abuzaid
7 months ago
HashMap Operations Complexity O(N)

HashMap Operations Complexity O(N)

1675112374.jpg
Mohamad Abuzaid
1 year ago
Security in Android App Development (1/3)

Security in Android App Development (1/3)

1675112374.jpg
Mohamad Abuzaid
7 months ago
Android Memory Leaks

Android Memory Leaks

1675112374.jpg
Mohamad Abuzaid
1 year ago
SOLID principles explained

SOLID principles explained

1675112374.jpg
Mohamad Abuzaid
1 year ago