Author

Surya

Browsing

In this blog, We’ll learn coroutines background processing by creating a small project, that simply displays an image to the UI.

Objective

  • Get Image from URL – So first we’re going to get an image from URL and obviously we can not do that on the main thread. So we need a background thread to do that. And we’re going to this with Coroutines.
  • Apply Processing – Next stuff is after downloading the image. We’re going to use another dispatcher to process that image. So here we’re going to apply a filter to that image. So that we transform it in a certain way. We’re going to convert it to black and white. We will do that in a separate coroutine for background processing.
  • Show it on ImageView – Finally, we’re going to show it on ImageView.

So it quite a simple idea, But the way we do it nicely. Because we are going to use coroutine for background processing. So while we are working live project we can understand how we can perform background processing with the bits of help of Coroutines.

Requirements

Importantly I want to mention here that there are some requirements for this example.

  • Android Studio – First of all you have to AndroidStudio installed in your machine.
  • Android Knowledge – You would have some Android development knowledge.

All right just go ahead and jump into the Android Studio.

Let’s create a new project with basic template. So first of all, I’m going to create a basic interface and you not have to worry about it, you can download the source code from bottom of this blog.

Add permission

Obviously, first thing we are going to download an image from server so we have to require Internet permission. So let open the android manifest add it.

    <uses-permission android:name="android.permission.INTERNET" />

I’m going to use this URL here, So this is what we will downloading and this is what we will processing.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="500dp"
        android:layout_height="500dp"
        android:scaleType="fitCenter"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone"
        app:srcCompat="@mipmap/ic_launcher" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Alright moving on we have a layout that has basically two elements. It has ProgressBar that will just show that something is going on in IO dispatcher. and it has an ImageView that is currently hidden. So this will become visible when we actually have something to display. and then we’ll hide the progressbar.

MainActivity

Create Filter

package com.backgroundprocessingexample

import android.graphics.Bitmap
import android.graphics.Color

object Filter {

    fun apply(source: Bitmap): Bitmap {
        val width = source.width
        val height = source.height
        val pixels = IntArray(width * height)
        // get pixel array from source
        source.getPixels(pixels, 0, width, 0, 0, width, height)

        var R: Int
        var G: Int
        var B: Int
        var index: Int
        var threshHold: Int

        for (y in 0 until height) {
            for (x in 0 until width) {
                // get current index in 2D-matrix
                index = y * width + x
                // get color
                R = Color.red(pixels[index])
                G = Color.green(pixels[index])
                B = Color.blue(pixels[index])
                val grey = (R + G + B) / 3
                pixels[index] = Color.rgb(grey, grey, grey)
            }
        }

        // output bitmap
        val bitmapOut = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        bitmapOut.setPixels(pixels, 0, width, 0, 0, width, height)
        return bitmapOut
    }
}

one things that I added here it is the Filter. Now this filter has a function fun apply(source: Bitmap) on a bitmap and it’s simply converted to a bitmap and It’s simply converted to a bitmap out to a another image.

What this filter does, It converts images to black & white. It does handle some processing because it goes pixel by pixel to convert it into black & white. That will take some processing power. So that a background job, So we can apply our coroutines to it. We can’t do it on the main thread or It should not do this in main thread.

    // Add Coroutines Dependency
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'

So here in the dependency first of all go ahead and copy the above dependencies. After adding these dependencies let go ahead and sync the project.

Now let’s open the MainActivity, So first i want to load image here from URL to local bitmap. then we want to put that bitmap in our ImageView. So I’m creating a kotlin function.

    private fun getImageFromUrl(): Bitmap =
            URL(IMAGE_URL).openStream().use {
                BitmapFactory.decodeStream(it)
            }

    private fun loadImage(bmp: Bitmap) {
        progressBar.visibility = View.GONE
        imageView.setImageBitmap(bmp)
        imageView.visibility = View.VISIBLE
    }

So this function simply returns a bitmap of whatever is returned from decode stream. Now Important thing is this is a network call. So we can not do that in main thread. So what we’ll like to do is we would like to open up a coroutines scope and do that call inside the scope on the IO dispatcher.

 coroutineScope.launch {
            val remoteImageDeferred = coroutineScope.async(Dispatchers.IO) {
                getImageFromUrl()
            }
            val imageBitmap = remoteImageDeferred.await()
            //loadImage(imageBitmap)
            launch(Dispatchers.Default) {
             val filterBitmap =   Filter.apply(imageBitmap)
                withContext(Dispatchers.Main) {
                    loadImage(filterBitmap)
                }

               // Log.i(MainActivity.TAG, "Default. Thread: ${Thread.currentThread().name}")
            }
        }

So let create a coroutines scope, here I’m going to open the main scope. Because we have to update UI from IO. Otherwise, we can’t update UI from another thread, It has to from main thread.

So the final output is

package com.backgroundprocessingexample

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.*
import java.net.URL

class MainActivity : AppCompatActivity() {

    private val IMAGE_URL = "http://androidwave.com/wp-content/uploads/2018/12/useful-tools-for-logging-debugging-in-android.png.webp"
    private val coroutineScope = CoroutineScope(Dispatchers.Main)


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        coroutineScope.launch {
            val remoteImageDeferred = coroutineScope.async(Dispatchers.IO) {
                getImageFromUrl()
            }
            val imageBitmap = remoteImageDeferred.await()
            //loadImage(imageBitmap)
            launch(Dispatchers.Default) {
             val filterBitmap =   Filter.apply(imageBitmap)
                withContext(Dispatchers.Main) {
                    loadImage(filterBitmap)
                }

               // Log.i(MainActivity.TAG, "Default. Thread: ${Thread.currentThread().name}")
            }
        }

    }

    private fun getImageFromUrl(): Bitmap =
            URL(IMAGE_URL).openStream().use {
                BitmapFactory.decodeStream(it)
            }

    private fun loadImage(bmp: Bitmap) {
        progressBar.visibility = View.GONE
        imageView.setImageBitmap(bmp)
        imageView.visibility = View.VISIBLE
    }
}

Conclusion

That all, this way you can perform background jobs using coroutines in Kotlin. Keep in touch for more coroutines tutorials

In this post, we gonna talk about firebase in-app messaging in android.

Overview

Firebase In-App Messaging helps you engage your app’s active users by sending them targeted, contextual message. Encourage them to use key app features. For example, you can send an in-pp message to get users to subscribe, watch a video, complete a level, or buy an items. I’m sure you guys familiar. If you had android app you often get in-app message.

You can customized message as card, banners, models, or images. You can also set up a trigger so that they appear exactly when they’d benefit. It is very similar to cloud messaging, except for messages sent to the app, not a device. So if you talk about cloud messaging.

Uses of In-App Messaging

You should use Firebase In-App Messaging to encourage exploration and discovery. Highlight a sale or coupon in your eCommerce app. Give clues or tips in your game. Prompt a like or share in your social media app. These types of things, So kind of different use case or messaging.

Key Capabilities of In App Messaging

  • Send relevant, engaging messages
  • Sends messages when they are most needed, while users are actually in your app.
  • Promote a big sale when users visit your In-app store. etc.
  • Target messages by audience or behavior.
    • Work with Analytics and Predictions to give you tools to deliver the message to the user you would most like to reach
    • Send messages based on user’s demographics, past behaviors, or even predictions of their future behaviors.
  • Create flexible, custom alerts –
    • You can create a flexible, custom alert and have the ability to customize your style appearance display triggers and content.
    • These will help you do everything from sending promotional offers to getting users to update a new version of the app.

Implementations Step

Now I want to show you, how you can setup and configure to use In App Messaging for Firebase.

  • Connect your app – Start by adding Firebase to your app in the firebase console
  • Integrates the SDK – Add the firebase In-App Messaging SDK to your app via Gradle.
  • Create your first message – Visit the Firebase console to write, customize, and target your first message.

Connect your app

Let’s open android studio, and create a simple project. For now It doesn’t have anything extra on it. It just MainActivity that’s empty.

The first thing we’re gonna to do we’re going to add this project to Firebase. Fo doing that we need to know is the package name, In this example, I’m using com.firebaseinappmessaging .

Now let’s go to the firebase console and go to the project. Then just add the app and go through the steps the adding an app by entering package name. Still, you are facing any issue, follow this article.

Now you have to download json file, So go to settings and download on google-service.json file in app folder.

Integrates the SDK

Now back to the Android Studio, Now we have to update Gradle file. So go to the project build.gradle file and add these dependencies. Something like below

    // Import the Firebase BoM
    implementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.5'
    implementation 'com.google.firebase:firebase-analytics-ktx:18.0.2'

Let’s sync the project, That all about configuration. For sending a test message you have to need AppInstaceId, Basically firebase console allow us send messaging to specific device.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="16dp"
        android:text="@string/warning_fresh_install"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/instanceIdText"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/instanceIdText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="@string/warning_fresh_install"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2"
        tools:text="Device Instance ID: 1234" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/eventTriggerButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@color/purple_200"
        android:text="@string/button_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.firebaseinappmessaging

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.google.android.gms.tasks.OnSuccessListener
import com.google.firebase.inappmessaging.FirebaseInAppMessaging
import com.google.firebase.inappmessaging.display.ktx.FirebaseInAppMessagingDisplayKtxRegistrar
import com.google.firebase.installations.FirebaseInstallations
import com.google.firebase.ktx.Firebase
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private lateinit var firebaseIam: FirebaseInAppMessaging
    //private lateinit var firebaseAnalytics: FirebaseAnalytics
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // firebaseAnalytics = FirebaseAnalytics.getInstance(this)
        firebaseIam = FirebaseInAppMessaging.getInstance()

        firebaseIam.isAutomaticDataCollectionEnabled = true
        firebaseIam.setMessagesSuppressed(false)

        eventTriggerButton.setOnClickListener { view ->
            //firebaseAnalytics.logEvent("engagement_party", Bundle())
            firebaseIam.triggerEvent("engagement_party")
        }

        // Get and display/log the Instance ID
        FirebaseInstallations.getInstance().id.addOnSuccessListener {
            instanceIdText.text = getString(R.string.instance_id_fmt, it)
            Log.d(TAG, "InstanceId: $it")
        }
//            .addOnSuccessListener(object : OnSuccessListener<InstanceIdResult> {
//                override fun onSuccess(instanceIdResult: InstanceIdResult) {
//                    val instanceId = instanceIdResult.id
//                    instanceIdText.text = getString(R.string.instance_id_fmt, instanceId)
//                    Log.d(TAG, "InstanceId: $instanceId")
//                }
//            })

        addClickListener()
    }
    private fun addClickListener() {
        val listener = InAppMessageClickListener()
        firebaseIam.addClickListener(listener)
    }

    private fun suppressMessages() {
        firebaseIam.setMessagesSuppressed(true)
    }

    private fun enableDataCollection() {
        // Only needed if firebase_inapp_messaging_auto_data_collection_enabled is set to
        // false in AndroidManifest.xml
        firebaseIam.isAutomaticDataCollectionEnabled = true
    }

    companion object {

        private const val TAG = "FirebaseInAppMessaging"
    }
}
package com.example.firebaseinappmessaging

import android.util.Log
import com.google.firebase.inappmessaging.FirebaseInAppMessagingClickListener
import com.google.firebase.inappmessaging.model.Action
import com.google.firebase.inappmessaging.model.InAppMessage


class InAppMessageClickListener : FirebaseInAppMessagingClickListener {

    override fun messageClicked(inAppMessage: InAppMessage, action: Action) {
        // Determine which URL the user clicked
        val url = action.actionUrl

        // Get general information about the campaign
        val metadata = inAppMessage.campaignMetadata

        Log.d("AppTest", "URL is: " + url)
        Log.d("AppTest", "Meta Data: " + metadata)
    }
}

In this post, we will learn exception handling in coroutines. Later on, we will know how to handle exceptions in a sequential program.

In coroutine, exception behavior depends on coroutines builder. So we already know that we have to two coroutines builders. We have launch and async. launch generates a job and async will generate a deferred that will give us a value. So based on that the behavior changes slightly.

Exception behaviour with launch

So for launch, As you know launch creates a job hierarchy. So exceptions will propagate instantly through the parent-child hierarchy and will immediately cause jobs to fail. So there is no delay and no way to catch it automatically. So what we need to do, we need to use try-catch inside the launch or we have a structure called an exception handler. So the summary of this is below

  • Propagates through the parent-child hierarchy
  • The exception will be thrown immediately and jobs will fail
  • use try-catch or an exception handler

In sort, launch automatically generates the exception and causes all the jobs to fail in the exception hierarchy. In coroutines, you won’t see the exceptions straight away. you will see the exception when you try to actually use the job or coroutines in the main thread. So if you call join on the job you will automatically join into main thread and then you will see the exception.

Behaviour with async

The async is slightly different. So async means we don’t have a hierarchy we just have the outcome. So the exception is deferred, and it will not be shown until the result is consumed. So if we call wait then we will see the exception. If we never call wait we will never see the exception. So what we need to do in this case is use the try-catch when we are calling await call. In sort we can say

  • Exceptions are deferred until the result is consumed
  • If the result is not consumed, the exception is never thrown
  • try-catch in the coroutine or in the await() call

So the difference is the launch propagated the exception through the job hierarchy immediately and kill the jobs. The async will only show the exception when you call await().

Exception handling in launch

Now we have a way to handle exceptions in launch. In coroutines we have a class named is CoroutineExceptionHandler

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            val myHandler = CoroutineExceptionHandler {coroutineContext, throwable ->
                Log.e(TAG,"Exception handled: ${throwable.localizedMessage}")
            }

            val job = GlobalScope.launch(myHandler) {
                Log.e(TAG,"Throwing exception from job")
                throw IndexOutOfBoundsException("exception in coroutine")
            }
            job.join()

            val deferred = GlobalScope.async {
                Log.e(TAG,"Throwing exception from async")
                throw ArithmeticException("exception from async")
            }

            try {
                deferred.await()
            } catch (e: java.lang.ArithmeticException) {
                Log.e(TAG,"Caught ArithmeticException ${e.localizedMessage}")
            }
        }
    }
}

Output

 E/MainActivity: Throwing exception from job
 E/MainActivity: Exception handled: exception in coroutine
 E/MainActivity: Throwing exception from async
 E/MainActivity: Caught ArithmeticException exception from async

Conclusion

In this post, we learned how to handle exceptions in coroutines. I have used this exception handling concept in the retrofit example. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Estimated reading time: 3 minutes

In this coroutines withContext example and we’ll see how we can change context easily in Coroutines. We’ll learn different ways to switch coroutine contexts also. In android aspects will see how to can switch the context main thread to another threads. So let’s started.

Uses of withContext

A function that is very commonly used in coroutines is withContext. Basically, withContext is allowed us to easily change context. It means It easily switches between dispatchers.

Suppose in an android application we have some heavy processing that we need to do. So we will do that in the Default Dispatchers then when the outcome completed then we want to switch to the Main Dispatchers in order to publish to display outcome on the UI. So we need a way to easily switch between context and the best way to do that is the withContext function. Because it’s very very lightweight.

Example of withContext

So let take a example see the below code

package com.asyncawaitexamplecoroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            launch(Dispatchers.Default) {
                Log.d(TAG,"First context: $coroutineContext")
                // default context
                withContext(Dispatchers.IO) {
                    Log.d(TAG,"Second context: $coroutineContext")
                    // IO context
                }
                Log.d(TAG,"Third context: $coroutineContext")
                // back to default context
            }
        }
    }
}

In this code, first I’m going to launch a coroutine in the default dispatcher. and I’m gonna log coroutineContext. So simply I logging out the context that we have. Then I’m gonna switch dispatchers to IO dispatcher. So using withContext(Dispatchers.IO) I’m gonna log the second context here. So once that is finished, so I’m gonna go back to my first context. So let log the coroutineContext again.

So I’m starting a coroutine in default context then I’m switching to IO and then I’m coming back to original. So let’s go head and run the code and see the output that we get from the LOGCAT.

Output

 D/MainActivity: First context: [StandaloneCoroutine{Active}@45522db, Dispatchers.Default]
 D/MainActivity: Second context: [DispatchedCoroutine{Active}@940c178, Dispatchers.IO]
 D/MainActivity: Third context: [StandaloneCoroutine{Active}@45522db, Dispatchers.Default]

Do we have our first context which is standalone coroutine whatever the name is system has given it. Then we are switching context. so we can that we have different Id(940c178) here.

That mainly I just want to show you the different ID that we get. Here is @45522db, @940c178, @45522db. So when we finish there we’re going back to same context that we have initially.

So basically it’s a very lightweight way to switch between context depending on type of functionality, type of processing that we need to do.

Conclusion

That all, in this blog we have learned coroutines withContext example in Kotlin android.  I hope it’s helpful for you. Keep reading 🙂

In this blog, I’ll show you uses of async and await function in coroutine. We’ll learn async and await coroutine functions with example. So let’s started.

Objective

The async is basically another way to start a Coroutine. Sometimes when you start a coroutine, you might need a value to be return from that coroutine back to the thread that launched it. So async just like launch, except it return a result.

Now the results, obviously since it’s returning in parallel, It can not return immediately. so think about an operation like network communication might have undetermined delay. But we still want to have that resolved that outcome at some point. So what async does, is return a result in the form of a deferred.

So deferred is basically promise that at the some point we will be able to get result but it’s not available right now. So it’s a future promise of a value.

async function

So this question is when we actually need the value, we have the await function. Important things is, this is a blocking call. It done on purpose obviously because at certain points we do need the value we can not proceed without it. So we have to wait for that value to be available.

So either the value is available straight away which is return immediately or If in value is not available it will pause the current thread until it is. So you can say If the value is available, it will return immediately or If the value is not available, it will pause the thread until it is, as simple as that. For achieving this functionality we have await function in coroutine.

How use await function

It a quite simple, so let say we have one suspended function that gives a random integer number. Now would have aync coroutine. So we have a GlobalScope.aysnc just like below. This will launch a coroutine that simply return call the suspended function.

suspend fun getRandom() = Random.nextInt(1000)

val valueDeferred = GlobalScope.async { getRandom() }
… // Do some processing here
val finalValue = valueDeferred.await( )

So it will give us a deferred. So this is the object of deferred then we do whatever processing we need in that program. Then we actually need the value we have to await() function. So this will pause the execution until the value is available for our main program. So we are simply waiting for a value to be available.

Example of async and await

Let’s take one example for better understanding. Let suppose you want to call a APIs right. For calling that API you might need some auth token. For example you might need API key and Access Token for calling API. It not a useful or a practical example but explain async concept, Its perfect.

So here I simply creating a runBlocking. and define 3 functions. these are below.

package com.asyncawaitexamplecoroutine

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlin.random.Random

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        runBlocking {
            val accessTokenDeferred = async { getAccessToken() }
            val apiKeyDeferred = async { getApiKey() }

            Log.i(TAG,"Doing some processing here")
            delay(500L)
            Log.i(TAG,"Waiting for values")

            val firstValue = accessTokenDeferred.await()
            val secondValue = apiKeyDeferred.await()

            textView.append("Access Token -> $firstValue \n")
            textView.append("API Key  -> $secondValue \n")
            textView.append(" User Details -> " + getUserDetails(firstValue,secondValue) )

        }
    }
    private suspend fun getAccessToken(): String {
        delay(1000L)
        val value = "ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab"
        Log.i(TAG,"Returning AccessToken $value")
        return value
    }

    private suspend fun getApiKey(): String {
        delay(2000L)
        val value = "ca6ee68b-73b8-41e1-8920-d20e349e36b6"
        Log.i(TAG,"Returning API key $value")
        return value
    }
    private suspend fun getUserDetails(accessToken:String, apiKey:String): String {
        delay(2000L)
        Log.i(TAG, " Access Token -> $accessToken API key ->$apiKey")
        val value = " Morris Kushwaha"
        Log.i(TAG,"Returning user details $value")
        return value
    }
}

It’s pretty straight forward, getAccessToken() and getApiKey() is aysnc in scope of run blocking. After that will call getUserDetails() function. In this function we simply logging access token and api and returning a value. So Important things is we are waiting a result from the first coroutine which will take 1 second.

Then second value is going to be deferred and it taking 2 second. After this simply calling userDetails function, that all. Let run this code and see this output

Output

I/MainActivity: Doing some processing here
I/MainActivity: Waiting for values
I/MainActivity: Returning AccessToken ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab
I/MainActivity: Returning API key ca6ee68b-73b8-41e1-8920-d20e349e36b6
I/MainActivity:  Access Token -> ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab API key ->ca6ee68b-73b8-41e1-8920-d20e349e36b6
I/MainActivity: Returning user details  Morris Kushwaha

So in logcat we get are Doing some processing here first after that Waiting for values. And getting AccessToken and after two second API key and finally Returning user details.

Conclusion

So basically async is a way for us to retrieve values from Coroutine. That all, so in this coroutine async and await example we’ll learned how we’ll make async call using Coroutine in android. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

FAQ

Coroutine related article

In this article, I will show, how to create a CardView in React Native, Which will work perfectly in android and iOS both. So let’s started.

Objectives

Basically, the purpose of the example is to design and CardView component in React Native and use it whenever we need it. Why it should component? The reason is we can use this CardView in other parts of the application. We might have a different item that we want to present in CardView.

Let suppose you’re building an app, how have to show products inside the card on the main screen. Now avoid repeating cardview style definition agin and again. We can create a separate component. Let create a new react native project.

Create a react native application

let move to IDE, create a new react native project and create separate package named is components. Here I’m creating a new file here name it Card.js. The name is up to you

import React from 'react';
import { View, StyleSheet } from 'react-native';

const Card = props => {};

export default Card;
 

So here I simply created a function component named is Card.js and export as default. Now it’s all about presentation here, So let style this card view

import React from 'react';
import { View, StyleSheet } from 'react-native';

const Card = props => {
  return (
    <View style={{ ...styles.card, ...props.style }}>{props.children}</View>
  );
};

const styles = StyleSheet.create({
  card: {
    shadowColor: 'black',
    shadowOffset: { width: 0, height: 2 },
    shadowRadius: 6,
    shadowOpacity: 0.26,
    elevation: 8,
    backgroundColor: 'white',
    padding: 20,
    borderRadius: 10
  }
});

export default Card;
  

That all, our components is ready for use. Let import this component in main app

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';

import {Colors} from 'react-native/Libraries/NewAppScreen';
import Card from './src/components/Card';

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView style={styles.container}>
        <Card style={styles.card}>
          <Text style={styles.sectionTitle}>Basic CardView Example</Text>
        </Card>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    margin: 16,
    alignItems: 'center', // Centered horizontally
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
    color: Colors.white,
  },
  card: {
    height: 200,
    width: '100%',
    backgroundColor: '#f18484',
    justifyContent: 'center', //Centered vertically
    alignItems: 'center', // Centered horizontally
  },
});

export default App;

In this blog, we will learn how to use retrofit with coroutines Kotlin in android application, with the help of an example. So we are actually building an application in android using Coroutines, Retrofit and MVVM, and so on. So lets started.

Objectives

Basically, the purpose of the project is to get the list of users information from the endpoints and display it to users in RecyclerView. I’m listing them below of these are objectives of this Retrofit coroutines example blog.

  • Get a list of user’s info from an endpoint using REST API. Basically
  • Use coroutines with Retrofit and MVVM
  • Display the user’s info in a RecyclerView

So the main idea is to show you, how you can build a professional application using a proper architecture with Retrofit and using coroutines to get some information from a webserver. so that is what we are building.

Requirements

Now, there are some requirements for this retrofit coroutines example app. These are listed below

  • Android knowledge
  • Retrofit
  • MVVM

So idea is, I’m not going to details of these, you have to basic idea of these items. You should know how retrofit works with MVVM. I’m going to focus, this example on coroutines that work with Retrofit and MVVM.

All right guys, so lets started quickly with this example app. Open AndroidStudio and create a new android project with some template.

Setting up the project

Let wait for sync of project, that recently you created. And first of all let’s add internet permission in AndroidManifest that is obvious, Because we are communicating with backend APIs. So we do need that

    <uses-permission android:name="android.permission.INTERNET"/>

All right then next step is we have to add below dependency in app build.gradle.

  • RecyclerView
  • Glide
  • Retrofit
  • Lifecycle extensions
  • Coroutines
    // RecyclerView dependency
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
    // Glide dependency
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    // Retrofit dependency
    implementation 'com.squareup.retrofit2:retrofit:2.7.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    // Lifecycle dependency
    implementation 'android.arch.lifecycle:extensions:1.1.1'
    // Coroutines dependency
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

Backend API Endpoint and JSON

So first of all, we require a REST API, that we have to consume in this project. You can use whatever you required. For now, I’m consuming this URL and json response is

{
  "page": 1,
  "per_page": 6,
  "total": 12,
  "total_pages": 2,
  "data": [
    {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "https://reqres.in/img/faces/1-image.jpg"
    },
    {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "https://reqres.in/img/faces/2-image.jpg"
    },
    {
      "id": 3,
      "email": "emma.wong@reqres.in",
      "first_name": "Emma",
      "last_name": "Wong",
      "avatar": "https://reqres.in/img/faces/3-image.jpg"
    }
    .
    .
    .
  ]
}

Create user Model

Now, we are following the MVVM design pattern in this coroutines example. So I’m creating a data class for parsing above JSON resonse. Let create a data class named is UserList.kt

package com.retrofitcoroutines.example.model

import com.google.gson.annotations.SerializedName

data class UserList(
    @SerializedName("page") val page: Int,
    @SerializedName("per_page") val per_page: Int,
    @SerializedName("total") val total: Int,
    @SerializedName("total_pages") val total_pages: Int,
    @SerializedName("data") val data: List<User>
)
 

Let’s create another data class named User.kt

package com.retrofitcoroutines.example.model

import com.google.gson.annotations.SerializedName

data class User(
    @SerializedName("id") val id : Int,
    @SerializedName("email") val email : String,
    @SerializedName("first_name") val first_name : String,
    @SerializedName("last_name") val last_name : String,
    @SerializedName("avatar") val avatar : String
)

Update the activity_main.xml

Now in main_activity has below layout, So we have a RecyclerView, then TextView in case of error, we can display a message. And we have a ProgressBar, so user know that is something is going in background. So its quite simple you know. So there are 3 element and we’re going to hide to show these element.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/usersList"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/listError"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        tools:text="Error"
        android:textColor="#FA1302"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/loadingView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout> 

Create a ViewModel

Let create a ViewModel named is ListViewModel. Here we simply fetching user list from backend server and passes that data to our MutableLiveData. Apart from this, we have a load error which generates an error message in case of API failure. and we have a loading MutableLiveData(), That let us know there is something happens in background.

package com.retrofitcoroutines.example.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.retrofitcoroutines.example.model.User
import com.retrofitcoroutines.example.remote.UserService
import kotlinx.coroutines.*

class ListViewModel : ViewModel() {

    val userService = UserService().getUsersService()
    var job: Job? = null
    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        onError("Exception handled: ${throwable.localizedMessage}")
    }

    val users = MutableLiveData<List<User>>()
    val usersLoadError = MutableLiveData<String?>()
    val loading = MutableLiveData<Boolean>()

    fun refresh() {
        fetchUsers()
    }

    private fun fetchUsers() {
        loading.value = true
        job = CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response = userService.getUsers()
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    users.value = response.body()?.data
                    usersLoadError.value = null
                    loading.value = false
                } else {
                    onError("Error : ${response.message()} ")
                }
            }
        }
        usersLoadError.value = ""
        loading.value = false
    }

    private fun onError(message: String) {
        usersLoadError.value = message
        loading.value = false
    }

    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }

} 

Connect ListViewModel to MainActivity

In the MainActivity we are instantiating the ListViewModel. Then we simply set up our RecycleView, Using a UserAdapter, That we’ll create below of the code, and then we are observing the ViewModel, which simply connecting Livedata from the ViewModel and proceeding to update the interface based on the information that we received. So all is that we need to do.

package com.retrofitcoroutines.example.view

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.retrofitcoroutines.example.R
import com.retrofitcoroutines.example.viewmodel.ListViewModel
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    lateinit var viewModel: ListViewModel
    private val userListAdapter = UserListAdapter(arrayListOf())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
        viewModel.refresh()

        usersList.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = userListAdapter
        }

        observeViewModel()
    }
    private fun observeViewModel() {
        viewModel.users.observe(this, Observer {countries ->
            countries?.let {
                usersList.visibility = View.VISIBLE
                userListAdapter.updateCountries(it) }
        })

        viewModel.usersLoadError.observe(this, Observer { isError ->
            listError.visibility = if(isError == "") View.GONE else View.VISIBLE
        })

        viewModel.loading.observe(this, Observer { isLoading ->
            isLoading?.let {
                loadingView.visibility = if(it) View.VISIBLE else View.GONE
                if(it) {
                    listError.visibility = View.GONE
                    usersList.visibility = View.GONE
                }
            }
        })
    }
}

Now create UserListAdapter

Simply create a RecyclerView Adapter and attached the user_item view to recycler as usual. The only different thing here is the extension function for ImageView to load the image which allows us to loan an image on ImageView based on the URL we have.

package com.retrofitcoroutines.example.view

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.retrofitcoroutines.example.R
import com.retrofitcoroutines.example.model.User
import com.retrofitcoroutines.example.utils.loadImage
import kotlinx.android.synthetic.main.item_user.view.*

class UserListAdapter(var users: ArrayList<User>): RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {

    fun updateCountries(newUsers: List<User>) {
        users.clear()
        users.addAll(newUsers)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, p1: Int) = UserViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
    )

    override fun getItemCount() = users.size

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(users[position])
    }

    class UserViewHolder(view: View): RecyclerView.ViewHolder(view) {

        private val imageView = view.userAvatar
        private val userName = view.userFullName
        private val userEmail = view.userEmail


        fun bind(user: User) {
            userName.text = user.first_name + " "+ user.last_name
            userEmail.text = user.email
            imageView.loadImage(user.avatar)
        }
    }
}

Here is item_user.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:background="#E4DDF3">

    <ImageView
        android:id="@+id/userAvatar"
        android:layout_width="80dp"
        android:layout_height="80dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/userFullName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/userAvatar"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Morris" />

    <TextView
        android:id="@+id/userEmail"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        tools:text="morris@androidwave.com"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/userAvatar"
        app:layout_constraintTop_toBottomOf="@+id/userFullName" />
</androidx.constraintlayout.widget.ConstraintLayout>

Write a extension function for ImageView

Here I have created a new package named is utils and writes below extension function.

package com.retrofitcoroutines.example.utils

import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.retrofitcoroutines.example.R

fun ImageView.loadImage(uri: String?) {
    val options = RequestOptions()
        .error(R.mipmap.ic_launcher_round)
    Glide.with(this.context)
        .setDefaultRequestOptions(options)
        .load(uri)
        .into(this)
}
  

That all about UI let setup Retrofit and connect it with project.

Setting up Retrofit

Let create a retrofit interface. Here I’m gonna set up a GET function for Retrofit. Inside this interface create a suspending function like below. It simply returns us a Response.

package com.retrofitcoroutines.example.remote

import com.retrofitcoroutines.example.model.UserList
import retrofit2.Response
import retrofit2.http.GET

interface UserApi {

    @GET("users")
    suspend fun getUsers(): Response<UserList>

} 

Create a UsersService

In this class, first of I have created a variable here is BASE_URL. After that I have created a function named is getUsersService() that simply returns UserApi that we just defined earlier.

package com.retrofitcoroutines.example.remote

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class UserService {
    
    private val BASE_URL = "https://reqres.in/api/";
    fun getUsersService(): UserApi{
       return Retrofit.Builder()
           .baseUrl(BASE_URL)
           .addConverterFactory(GsonConverterFactory.create())
           .build()
           .create(UserApi::class.java)
    }
}

That all done, let’s go ahead and run the code and see if it works. It’s working so we have all users that return from APIs in the context of coroutines. Basically, in this example, we have two coroutines because first, we are calling with Dispatchers.IO and finally we are calling Dispatchers.Main. So way we can update UI in main. thread. That code I already added in ViewModel, for reference I adding again

CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response = userService.getUsers()
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    users.value = response.body()?.data
                    usersLoadError.value = null
                    loading.value = false
                } else {
                    onError("Error : ${response.message()} ")
                }
            }
        } 

Conclusion

So that is it, So we learned how to use Retrofit with coroutines in Kotlin| Android.  I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Download Source Code

Retrofit coroutines error handling

will publish a complete article on that, For now you can follow this article

Retrofit with coroutines

This is a sample app thats created. Please follow this article only

In this post, we will talk about dispatchers, we will learn what is dispatchers in Kotlin Coroutines? How it works in Coroutines. will learn all type of dispatchers that is available in Coroutine.

What is Dispatchers in Coroutines

A dispatcher basically determines which thread or thread pool the coroutine runs on. So you don’t necessarily need to define a dispatcher if you don’t want to. You can run coroutine very easily like in previous blog we’ve done so far, without specifying which dispatcher we want. However, if you want to bit more precise on how your coroutine runs, you can specify a dispatcher. In android, the application dispatcher plays an important role to manage different types of tasks.

Types of Dispatchers in Coroutines

Majorly 4 different types of dispatchers are available in coroutines, depending on the task specificity. So some dispatchers are more suitable for network communications, others are for processing a large amount of data, some available for communicating with UI, and so on.

Basically, you decide which dispatchers your coroutines will run based on what the coroutines actually do.

So we have few common dispatchers in Coroutine, that we use. I have listed them here, so that we can see which dispatcher is for which kind of task.

  • Main Dispatchers: we will use the Main dispatcher when we want to update the UI
  • Default Dispatchers: Useful for performing CPU intensive work
  • IO Dispatchers: Useful for network communication or reading/writing files
  • Unconfined Dispatchers: Starts the coroutine in the inherited dispatcher that called it
  • newSingleThreadContext(“MyThread”) – Forces creation of a new thread

How we can use Dispatchers

Basically we have to pass a parameter to the launch function like below

   launch(Dispatchers.Default) {
	// do some task here
   }

1. Main Dispatchers

Dispatchers.Main is for updating UI driven applications. So for example, android app is very UI focused. So we will use the main dispatchers when we want to update UI. You can say, we will use the Main Dispatcher when we want to update the UI. You guys already know that the UI cannot be updated unless you are on UI thread, which means the main thread.

So let’s go ahead and take an example for better understanding. Let’s open the Android Studio and create a new project. Once the project is synced then add the Coroutines in app/build.gradle

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"

Now paste the below code inside the onCreate() method

package com.coroutineskotlinexample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            launch(Dispatchers.Main) {
                Log.d(TAG, "Main dispatcher. Thread: ${Thread.currentThread().name}")
            }
        }
    }
}

As you saw, in the above code block I launch coroutines in our Main Dispatchers. Inside the block we log the name of the thread, just to see which thread on.

2. Default Dispatchers

Default dispatchers is very useful for CPU intensive work. So things like data processing, image processing. That kinds of work should usually be done with the default dispatchers.

package com.coroutineskotlinexample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            launch(Dispatchers.Default) {
                Log.i(MainActivity.TAG, "Default. Thread: ${Thread.currentThread().name}")
            }
        }
    }
}

Let run the above code, and the logcat, Here as you see the default dispatchers is running on a worker thread. the output is below

 I/MainActivity: Default. Thread: DefaultDispatcher-worker-1

3. IO Dispatchers

This is very useful for network communication or reading/writing files. So any Input Output operations should be go through this IO dispatchers.

import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            launch(Dispatchers.IO) {
                Log.i(MainActivity.TAG, "IO. Thread: ${Thread.currentThread().name}")
            }
        }
    }
}  

IO Dispatchers also run in worker thread, So this is kind of internal to Coroutines. So we don’t really have too much control. We simply know that, the IO Dispatchers is specific for input/output operations.

Output
I/MainActivity: IO. Thread: DefaultDispatcher-worker-1

4. Unconfined Dispatchers

Unconfined dispatchers start the coroutine in the inherited dispatcher that called it. So if you have a coroutine that works on Main dispatchers and then you start another coroutine as unconfined. It will start the coroutine in the inherited dispatcher which is the main.

So in this case we are not defining what dispatcher we want. We let the system decide for us.

package com.coroutineskotlinexample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
//            launch(Dispatchers.Main) {
//                Log.i(TAG, "Main dispatcher. Thread: ${Thread.currentThread().name}")
//            }

            launch(Dispatchers.Unconfined) {
                Log.i(TAG, "Unconfined1. Thread: ${Thread.currentThread().name}")
                delay(100L)
                Log.i(TAG, "Unconfined2. Thread: ${Thread.currentThread().name}")
            }
        }
    }
}
Output
 I/MainActivity: Unconfined1. Thread: main
 I/MainActivity: Unconfined2. Thread: kotlinx.coroutines.DefaultExecutor

let run the code and see. So we can see that Unconfined one is running on main thread. However we delaying for 100 milliseconds, and Unconfined2 is actually running a different thread. So you can see that the Coroutines has shifted from one thread to another thread when it was resumed.

5. newSingleThreadContext(“MyThread”)

Now we have another dispatcher which is a new single thread context. And this simply creates a new thread for us. So It forces the creation of a new thread? This shouldn’t really be used that often because new threads are very expensive, and coroutines are very very lightweight.

So we should try to use coroutines as they are intended. But sometime might want the situation, so its. good to know that you have this possibility.

package com.coroutineskotlinexample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.launch
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            launch(newSingleThreadContext("MyThread")) {
                Log.i(
                    MainActivity.TAG,
                    "newSingleThreadContext. Thread: ${Thread.currentThread().name}"
                )
            }
        }
    }
}     
Output
I/MainActivity: newSingleThreadContext. Thread: MyThread

As I previously explained, newSingleThreadContext basically creates a new thread, specifically for our coroutines. So here on logcat we saw that thread is MyThread. Now like said this is a bit expensive in term of resources. So should really use it unless you absolutely have to.

Conclusion

So that how you would use dispatchers to perform operations, based on the type of operation that you have. Let puts all dispatchers in a single programme.

package com.coroutineskotlinexample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            launch(Dispatchers.Main) {
                Log.i(TAG, "Main dispatcher. Thread: ${Thread.currentThread().name}")
            }

            launch(Dispatchers.Unconfined) {
                Log.i(TAG, "Unconfined1. Thread: ${Thread.currentThread().name}")
                delay(100L)
                Log.i(TAG, "Unconfined2. Thread: ${Thread.currentThread().name}")
            }

            launch(Dispatchers.Default) {
                Log.i(TAG, "Default. Thread: ${Thread.currentThread().name}")
            }

            launch(Dispatchers.IO) {
                Log.i(TAG, "IO. Thread: ${Thread.currentThread().name}")
            }

            launch(newSingleThreadContext("MyThread")) {
                Log.i(TAG, "newSingleThreadContext. Thread: ${Thread.currentThread().name}")
            }
        }
    }
}
 
Output
 I/MainActivity: Unconfined1. Thread: main
 I/MainActivity: Default. Thread: DefaultDispatcher-worker-1
 I/MainActivity: IO. Thread: DefaultDispatcher-worker-2
 I/MainActivity: newSingleThreadContext. Thread: MyThread
 I/MainActivity: Unconfined2. Thread: kotlinx.coroutines.DefaultExecutor

In this blog, we will learn about Coroutines Job in Koltin. Using the Coroutines Job how we can handle the peace of code that is running in the background. So let’s started.

What is Jobs

Basically, Job in the context of Coroutines is handled on that Coroutines piece of code that is running in background. So a .launch() call returns a Job. Using that Job you can manipulate the lifecycle. Let briefly explain about Coroutines Jobs

  • Jobs allows us to manipulate the coroutine lifecycle
  • Jobs have a hierarchy, So Jobs live in the hierarchy of other Jobs

Job Example

//Jobs hierarchy
Job1 {
	Job2 { }
	Job3 {
		Job4{ }
	}
}

You have a Job here that has two children( Job1 and Job2 ) and one of the children has another child. So you have a hierarchy of Jobs. So this is how you can create a Job or a Job within a hierarchy. Let’s take one more example.

Job Example

val job1 = GlobalScope.launch {
	coroutineScope {
		val job2 = launch {
		// processing
	}
}

In this example, You have a job here, and it created when we launch on GlobalScope. Inside that global scope, we created a coroutine scope and inside that, we launch our job2. So in this particular example job2 lives inside job1.

Job lifecycle variables and method

So you can access lifecycle variables and methods using the job. These are

  • cancel()
  • join()

So things like cancel() that allow us to cancel a job and join which basically join the coroutine to the current thread, to the main thread usually.

Now importantly If a job is cancelled, all its parents and children will be cancelled too. So these Job within a hierarchy depends on each other. and one is cancelled then other will be cancelled as well. Let’s understand it below example

Example of Job

So let go ahead a create few job in a kotlin class in main function, just like below

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking {
        val job1 = launch {
            println("Job1 launched")
        }

        job1.invokeOnCompletion { println("Job1 completed") }
    }
}

As you have seen, first I have created runBlocking() to create a coroutine context or coroutine scope. And inside here I’m gonna have a job named is job1.

So after I have created and launched Job 1, on completion what I would like to do, just println(“Job1 completed”) using invokeOnCompletion(). So this is an invokeOnCompletion method a hook that we can use to process some code when the job is completed, whether it canceled or finished by itself. Let go ahead and run the code as it now

Output

Job1 launched
Job1 completed

As you have seen, job has launched and completed. Now we have job1 launched and we use that job object to attached some fictionality to on it completion.

Cancel the Job in Coroutines

Using the above block of code, I would like to cancel this job it is still running and see what its the outcome will be. So, first of all, I need to put a delay here inside the job otherwise the job would run immediately.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking {
        val job1 = launch {
            delay(3000L)
            println("Job1 launched")
           
        }

        job1.invokeOnCompletion { println("Job1 completed") }

        delay(500L)
        println("Job1 will be canceled")
        job1.cancel()
    }
}

Output

Job1 will be cancelled
println("Job1 will be cancelled")

Now importantly println(“Job1 launched”) is not execute anymore because we are having a delaying half a second and then we are saying to jump on canceled, then we are canceling it. So let run this code and see the output. first, call println(“Job1 will be canceled”) then job1.invokeOnCompletion { println(“Job1 completed”) }. invokeOnCompletion run whether the job finishes by itself or is canceled. So we are getting ‘Job1 completed’

Create a hierarchy inside the Job in Coroutine

Now what I would like to show you is, how we can create a hierarchy inside the Job. then see what happens when we actually cancel the Job. and whats happens in that Job hierarchy.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking {
        val job1 = launch {
//            delay(3000L)
            println("Job1 launched")
            val job2 = launch {
                println("Job2 launched")
                delay(3000L)
                println("Job2 is finishing")
            }
            job2.invokeOnCompletion { println("Job2 completed") }

            val job3 = launch {
                println("Job3 launched")
                delay(3000L)
                println("Job3 is finishing")
            }
            job3.invokeOnCompletion { println("Job3 completed") }
        }

        job1.invokeOnCompletion { println("Job1 completed") }

        delay(500L)
        println("Job1 will be cancelled")
        job1.cancel()
    }
} 

So inside the Job1, we have launched Job1 launched. In this hierarchy I have created 2 more jobs, that is Job2 and job3. Inside these jobs, we have a println(). Here we have a delay of 3 seconds. After that, we have again println. At the last we calling invokeOnCompletion(). All done let go ahead and run this code.

Job1 launched
Job2 launched
Job3 launched
Job1 will be cancelled
Job2 completed
Job3 completed
Job1 completed

All right, as you have Job1 launched, Job2 launched and Job3 launched. Now impotently we’re never getting Job2 is finishing and Job3 is finishing, why because we are getting job1 will be cancelled. Then we are proceeding to actually cancel that job. and we can see (Job1 will be cancelled) that we are cancelling Job1, therfore we are cancelling job2 and job3. That why we are getting Job2 completed, Job3 completed and then Job1 completed. So the whole hierarchy will be cancelled, If one of the job will be cancelled.

So that is how you play around with jobs. You can the job object to invoke lifecycle methods on that particular Coroutines.

Conclusion

That all about jobs in Coroutines. In this blog, we have learned how jobs allow us to manipulate the coroutine lifecycle, and how the Jobs hierarchy works. I hope it will help you a lot, I would like to invite you to read our coroutines series. Thanks for reading

Happy coding 🙂

In this blog, we will learn suspending functions in a coroutine. I will show you how it works in coroutine android. What needs of these in a coroutine, etc. How they make callbacks seamless. So let’s started.

What is suspending functions

The idea behind suspending functions is quite easy. It simply a function that can be run in a coroutine. In simple words, a functions that can be run in a coroutine, and the main advantage I would say of suspending functions is that they make callbacks seamless.

Need of suspending functions

Actually In coroutine, If you try to access a function from coroutine you’ll get an error unless you make it a suspending function

Suspending functions example

let take a very basic example of suspending functions and understand how it makes developer life easier. So let started

In this example, I’m going to use the function named composeMessage() and one variable named count that equal to zero. So using this variable we simply track the number of calls to suspend the function. Let see the improvements things is the count (variables) is part of our main application. However, suspending functions composeMessage() will be part of Coroutine. Here is how easy it is to synchronize between our main thread and a Coroutine.

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

var count = 0

fun main() {
    
 }

suspend fun composeMessage() {
    delay(500L)
    println("Android!")
    count++
}

Create improveMessage()

Let’s go ahead and create another function let say improveMessage(). This function also does kind of the same things. So here is delay is 1 second and simply println a message somethings like below.

suspend fun improveMessage() {
    delay(1000L)
    println("Suspend functions are cool")
    count++
}

Call functions in main thread

Now in our main program, let go head and launch these two coroutine just like below.

  import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

var count = 0

fun main() {
    GlobalScope.launch { composeMessage() }
    GlobalScope.launch { improveMessage() }
    print("Hi, ")
    Thread.sleep(2000L)
    println("There have been $count calls so far")
}

suspend fun composeMessage() {
    delay(500L)
    println("Android!")
    count++
}

suspend fun improveMessage() {
    delay(1000L)
    println("Suspend functions are cool")
    count++
}

Output

Now let run the programme and the expected out is below.

Hi, Android!
Suspend functions are cool
There have been 2 calls so far

So in console, we are getting Hi, half a second later. We are getting the Android! . Then we are getting a second message from improveMessage() function. And then we are checking the variable count. An important thing we are accessing that variable in the main thread that has been updated by the Coroutine. So this is how synchronization works. It is very easy to update functions or variables in the main thread from the Coroutine.

Conclusion

It’s not a very complicated fictionality and it’s probably not very useful in a real-world situation. But I’m sure it does highlight how we can run a function from a Coroutine. also importantly how we can update local variables from a Coroutine.

I hope this article helps you a lot, I would like to suggest you read our coroutines series. 

Exit mobile version