Coroutines are a way to handle multithreading in Kotlin, read more about it from the official docs:

https://kotlinlang.org/docs/coroutines-overview.html

An example of a Coroutine in Kotlin

val runBlocking = runBlocking {
  sleep(5)
  delay(1_000L)
  launch {
    delay(1_100L)
    note("inside launch")
  }
  note("outside launch")
}

Introducing the suspend keyword

coroutineScopes need to be in wrapping suspend:

suspend fun coroutineFunction(): String {
  return coroutineScope {
    launch {
      println("test")
    }
    "we return this string"
  }
}

runBlocking { println(coroutineFunction()) }

Making Asynchronous API calls using Coroutines

suspend fun call2Apis() {
  val call1 = async {
    delay(1_000L)
    println("got data from api1 @ ${Instant.now()}")
    "some data from api1"
  }
  val call2 = async P
    delay(1_500L)
    println("got data from api2 @ ${Instant.now()}")
    "some data from api2"
  }

  println(call1.await() + " ${Instant.now()}")
  println(call2.await() + " ${Instant.now()}")

}

runBlocking { call2Apis() }
sleep(2)

Sharing states between Coroutines

Simply return a coroutineScope.

suspend fun call2Apis() {
  return coroutineScope {
    val call1 = async {
      delay(1_000L)
      println("got data from api1 @ ${Instant.now()}")
      "some data from api1"
    }
    val call2 = async P
      println(call1.isCompleted) // false
      println(call1.await()) // pause and wait for call1 to complete..
      delay(1_500L)
      println("got data from api2 @ ${Instant.now()}")
      "some data from api2"
    }

    println(call1.await() + " ${Instant.now()}")
    println(call2.await() + " ${Instant.now()}")

  }
}

runBlocking { call2Apis() }
sleep(2)

Run tasks as Global Scope

runBlocking {
  GlobalScope.launch {
    //
  }
}