Async Adventures Part I: Deciphering Kotlin Coroutines for a Smooth Coding Journey šŸš—šŸŒ

Kotlinā€™s Coroutine Circus: From Suspensions to Spectacles!

Ā·

6 min read

From Poetry to Programming: My Personal Code Odyssey.

Before the allure of writing and dreaming codes ensnared me (I get nightmares at times), I reveled in the world of words as a storyteller and poet. When I stepped onto the tech stage, it felt like a legion of terminologies was challenging me to a duel. Remembering my high school days, where turning complex science concepts into tales made them more palatable, I wielded storytelling as my sword once more. This narrative technique became my beacon and enchanted my students during my tenure as a tech bootcamp instructor in the U.S.

So, allow me to invite you on a narrative journey into the enthralling domain of Kotlin Coroutines!

Welcome to the exciting world of Kotlin Coroutines! Imagine you have many friends (tasks) trying to share their stories at the same time without interrupting one another. Thatā€™s what Coroutines help us achieve in our code!

šŸŽÆ A Simple Look at Coroutines

In coding, sometimes, we want our programs to do multiple things at once. Coroutines help us organize this chaos. Think of them as friendly guides, helping our tasks take turns so that they donā€™t talk over each other. Unlike other methods, which can be heavy and confusing, Coroutines are light and easy!

Other coding tools like Callbacks and Futures can make our code messy, but with Coroutines, we keep things neat and easy to read.

šŸ›‘ Understanding Asynchronous Programming

Imagine a park where kids (our tasks) play different games at the same time. Thatā€™s Asynchronous Programming. Each kid is doing their own thing without waiting for the others to finish.

šŸ§³ Note: In simpler terms, itā€™s about doing many things at once in our code.

šŸš— Meet Kotlin Coroutines: Our Friendly Guide

Coroutines help our tasks wait their turn without stopping everything else. They tell one task, ā€œHey, take a short break while others work,ā€ and then bring it back when itā€™s its turn.

šŸ§³ Note: This ā€œtake a short breakā€ magic comes from a special word suspend. When we see it in our code, it means that the function can pause and resume later.

suspend fun enjoyTheView() {
    println("Enjoying the beautiful scenery!")
}

Before embarking further, equip your coding backpack by adding these potions (dependencies) to build.gradle (Module :app) and sync:

dependencies {
//Other dependencies
...

//You can upgrade to 1.7.1
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' 
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
}

šŸŒ‰ Writing Our First Coroutine

To start a Coroutine, we use launch. Think of it as starting a new adventure for our tasks. The suspend word lets our functions take short breaks.

šŸ§³ Note: Using words like launch and suspend, we can easily control how our tasks run.

import kotlinx.coroutines.*

fun main() {
    runBlocking {
        launch {
            enjoyTheView()
        }
    }
}

šŸ“– About runBlocking: Think of runBlocking as a campsite. Everything inside it waits until all tasks (or adventures) are done. In Android, itā€™s mostly for quick tests or examples, not for real apps! It blocks the current thread until the coroutine inside it completes. This is not recommended for Androidā€™s onCreate method as it can lead to UI freezing.

šŸ—ŗļø Exploring More with Coroutines

Using Coroutines, we can easily make tasks wait or run immediately. For example, with delay(), we can make a task wait a bit before continuing.

suspend fun exploreTheLand() {
    delay(2000L) // Wait for 2 seconds
    println("Discovered a new place!")
}

fun main() = runBlocking {
    launch {
        exploreTheLand()
    }
    println("Starting our journey!")
}

If you try the example above, youā€™ll first see ā€œStarting our journey!ā€ and, after a 2-second wait, ā€œDiscovered a new place!ā€.

šŸ“– Updating UI in Android: In real Android apps, we might want to update our screen (or UI) after a task. Using Coroutines, we can do this with withContext(Dispatchers.Main). This tells our app, "Hey, update the screen now!"

For instance, in an Android Activity:

GlobalScope.launch {
    val data = fetchData()  // Some function to fetch data
    withContext(Dispatchers.Main) {
        updateUI(data)  // Function to update your appā€™s screen
    }
}

Remember, to update the UI, always use withContext(Dispatchers.Main).

Also, remember to be careful when using GlobalScope as itā€™s not tied to any lifecycle, and the launched coroutines will not be canceled when your activity is destroyed. Itā€™s often better to use a scope tied to the activity lifecycle like lifecycleScope or viewModelScope.

You would need to add these dependencies in your build.gradle (Module :app) and sync: (Weā€™ll talk more about this in a subsequent chapter.)

 implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
 implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'

šŸŽ¬ Playing Around With Wholesome Coroutine Adventure

Letā€™s imagine youā€™re orchestrating a grand festival in the village square. This festival has three main events: a dance performance, a magic show, and fireworks. Weā€™ll use Kotlin Coroutines to make sure each event happens seamlessly.

import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.Main

fun main() = runBlocking {

    // Dance Performance
    val dancePerformance = async {
        startDancePerformance()
    }

    // Magic Show
    launch {
        magicShow()
    }

    // Wait for the dance to finish before starting fireworks
    dancePerformance.await()

    // Fireworks
    withContext(Main) {
        grandFireworks()
    }

    println("What a magical festival!")
}

suspend fun startDancePerformance(): String {
    delay(2000L) // The dance performance lasts 2 seconds
    println("šŸ’ƒ The dance performance was mesmerizing!")
    return "Dance Done!"
}

suspend fun magicShow() {
    delay(1000L) // The magic show takes a second to mesmerize the audience
    println("šŸŽ© Wow, did that magician just pull out a rabbit?")
}

suspend fun grandFireworks() {
    delay(500L) // Half a second pause before the grand fireworks
    println("šŸŽ† Boom! The sky is painted with colors!")
}

Breaking Down Our Festival:

  1. Asynchronous Programming: Our festival is bustling with multiple events happening. Some can happen at the same time (dance and magic show), while some wait for others (fireworks wait for the dance). This is the essence of asynchronous programming.

  2. Using Coroutines: We use launch and async to start our events. launch starts an event without waiting for it to finish while async starts an event and lets us await its result.

  3. Suspend Functions: Notice the word suspend before our functions? These allow our events to take breaks (like the delays in our events) without stopping other events.

  4. Updating the Main Event: Our grand fireworks, which are the main event, are executed on the main thread (withContext(Main)) to ensure everyone in the village witnesses them.

  5. Running the Festival: We wrap everything in runBlocking to ensure our main function doesn't finish before all our events are completed.

When you run the example, youā€™ll see the magic show start, followed by the dance, and once the dance ends, the grand fireworks illuminate the sky, concluding our festival.

šŸŒ… Whatā€™s Next?

The Weekend Nerd! šŸ˜‰

Thereā€™s so much more to explore, like ā€œCoroutine Scopesā€ and ā€œDispatchers.ā€ But for now, letā€™s relax and enjoy( the weekend šŸ¤“) what weā€™ve learned.

Wrapping Up: Mixing fun stories with code makes learning Kotlin Coroutines an exciting journey. Stick around for more adventures and happy coding! šŸŽ’šŸ—ŗļø

Ā