Category

Coroutines

Category

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 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…

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…

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…

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…

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…

Exit mobile version