Android Development

Google's android guide Home Contact

Couroutines in Android

Multi-threading approach in Android allows to handle tasks on separate thread (or threads) without blocking the Main UI thread. There are common solutions such as Asyntask (currently deprecated), Thread Pool Executor and Rx Java. There is also option to use third party libraries, such as Volley and Retrofit. Coroutines provide a purely Kotlin based lightweight solution, with little risk for memory leaks and many other advantages. Coroutines can run code concurrently, without blocking the main thread. They completely eliminate use of callbacks for switching from one thread to another. They are considered light-weight threads, but more strictly, they are not threads, but just blocks of code used by functions running on one or more predefined threads. Coroutines can be paused, stopped and resumed on the thread they run, eliminating need of unnecessarily keeping thread idle. Coroutines, thus introduced a new way of writing asynchronous, non-blocking code, similar to threads, which can communicate with each other but much light-weight. If needed, spawning thousands of coroutines can be easily done unlike same for threads, with advantages of being much faster and requiring much fewer resources than threads.

Main Coroutine Features

  • Coroutines are not bound to a specific thread and can suspend code execution in one and resume in another.

  • Multiple coroutines can run on a single thread, with each having its own lifecycle, due to suspension functions, which doesn't block the thread where coroutine runs, and allow to start, pause and resume execution of a coroutine, within coroutine context.

  • All coroutines must run inside a Coroutine Scope, which defines the coroutine context and manages lifecycle throughout their execution. Cancelling a scope, destroys all coroutines within it too. There are many kind of scopes used for Coroutines: Global Scope (coroutine maximum lives as long as application), LifeCycle Scope (coroutine maximum live with the life of Activity), ViewModel Scope (coroutine will live maximum with ViewModel's life), runblocking (creates temporary scope and blocks current thread until its child coroutines complete),Coroutine Scope (with the activity, fragment or ViewModel) or create Custom Scope based on specific use case not tied to standard android components or library.

  • A coroutine can be executed using various dispatchers, which decide which thread to use, switch over to or from etc. It is an optional feature, but helps precise determination which thread or thread pool coroutine runs on. Some of disptachers include Dispatchers.Default (for CPU intensive work), Dispatchers.IO (for I/O-bound tasks, reading from or writing to files, making network requests, or working with databases), Dispatchers.Main (for tasks on the main (UI) thread), Dispatchers.Unconfined (without any specific thread). If no dispatcher specified, coroutine will use default dispatcher with builders used such as launch, async etc.

  • To create and start a new coroutine, use one of the available builder functions: runBlocking (blocks underlying thread), launch (lauch coroutine concurrently), or async (launch coroutine asynchronously and return result) .

Kotlin's Suspend Function

This kind of function can be started, paused and resumed. It is declared by using suspend keywork beforethe function name. They can be only called from a coroutine or another suspend function. Coroutines are not bound to any specific threads, so they can be suspended in one thread and resumed in another, by use of suspend function. No resources are consumed while a function is suspended. Suspending a function stops any task defined by the function and resumed later in the same or another thread. A thread unlike coroutine can only be blocked.

An example to show how suspend function defined within coroutine for Android. If decalred outside, compiler will throw error.

     
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?


  •