Android Development

Google's android guide Home Contact

Coroutines in Android

Multi-threading in Android allows tasks to be handled on separate threads without blocking the main UI thread. Common solutions include AsyncTask (now deprecated), ThreadPoolExecutor, and RxJava. Third-party libraries such as Volley and Retrofit are also popular. Coroutines offer a purely Kotlin-based, lightweight solution with minimal risk of memory leaks and several other advantages. They enable concurrent execution of code without blocking the main thread, eliminating the need for callbacks to switch between threads. Coroutines are often referred to as lightweight threads. However, strictly speaking, they are not threads; they are blocks of code executed by functions on predefined threads. Coroutines can be paused, stopped, and resumed on the threads they run on, avoiding the inefficiency of keeping threads idle. This makes them an effective tool for writing asynchronous, non-blocking code that is faster and requires fewer resources compared to traditional threads.

Main Coroutine Features

  • Coroutines are not tied to specific threads and can suspend execution on one thread and resume on another.

  • Multiple coroutines can run on a single thread, each with its own lifecycle. Thanks to suspension functions, coroutines do not block the thread they run on, allowing them to start, pause, and resume within a coroutine context.

  • All coroutines must run inside a Coroutine Scope, which defines the coroutine context and manages their lifecycle. Cancelling a scope destroys all coroutines within it. Common coroutine scopes include:
    • GlobalScope: Coroutines live as long as the application.
    • LifecycleScope: Coroutines live as long as the activity or fragment lifecycle.
    • ViewModelScope: Coroutines live as long as the ViewModel lifecycle.
    • runBlocking: Creates a temporary scope and blocks the current thread until its child coroutines complete.
    • CoroutineScope: Tied to custom use cases, independent of standard Android components.

  • Coroutines use dispatchers to specify the threads they run on. Dispatchers include:
    • Dispatchers.Default: For CPU-intensive tasks.
    • Dispatchers.IO: For I/O-bound tasks such as file operations, network requests, or database interactions.
    • Dispatchers.Main: For tasks on the main (UI) thread.
    • Dispatchers.Unconfined: Without a specific thread or thread pool.
    If no dispatcher is specified, the default dispatcher is used depending on the coroutine builder, such as launch or async.

  • Coroutine builders include:
    • runBlocking: Blocks the underlying thread.
    • launch: Launches a coroutine concurrently without returning a result.
    • async: Launches a coroutine asynchronously and returns a result.

Kotlin's Suspend Function

Suspend functions are functions that can be paused and resumed. They are declared using the suspend keyword before the function name and can only be called from a coroutine or another suspend function. Suspend functions enable coroutines to be suspended on one thread and resumed on another without consuming resources during suspension. This differs from threads, which can only be blocked but not suspended.

Here is an example of defining a suspend function within a coroutine for Android. If declared outside of a coroutine, the compiler will throw an error:

import kotlinx.coroutines.*

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

suspend fun fetchData() {
    delay(2000) // Simulates a network or time-consuming operation
    println("Data fetched successfully!")
}

In this example, the fetchData() function is declared as a suspend function. It uses delay(), a suspending function, to pause execution for 2 seconds without blocking the thread. The coroutine resumes execution once the delay is over.

     
class MainActivity : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Do not call suspend function here.
 
         // Launch coroutine.
        GlobalScope.launch{
        
         // Call suspend function here or from another suspend function only.
       
        } 
 
    }
}

Coroutine Example Code

Here is Kotlin coroutine code that performs an asynchronous network call using the async and await keywords:


import kotlinx.coroutines.*
import java.net.URL

fun main() {
    // create a new coroutine scope
    runBlocking {
        // launch a new coroutine in the scope
        val job = launch {
            // create a new coroutine within the scope
            val result = async {
                // make an asynchronous network call
                URL("https://www.zyasin.com/jsonexample2.json").readText()
            }
            // wait for the result of the network call and print it
            println(result.await())
        }
        // wait for the coroutine to complete
        job.join()
    }
}
    

Complete code for a network call using Android coroutine can be found at github URL: Coroutine for Fetching JSON data.

Quiz Questions


  • Coroutines are thought of as light-weight threads. Threads are managed by Operating System. Is that true for coroutines?
  • For a coroutine task running in GlobalScope, can it be destroyed before application is killed?


  •