C1CTech

Android Handler with Example

In the previous article, we have talked about Thread . As we know it is possible to access UI components inside the worker thread using some of the methods like

But there is one more alternative in android i.e Handler which also allows you communicate back with the UI thread from other background thread. In this article, we will talk about Handler in brief.

Main Thread

Android handles all the UI operations and input events from one single thread which is known as Main or UI thread. Android collects all events in this thread in a queue and processes this queue with an instance of the Looper class.

Android supports Thread class to perform asynchronous processing.

Why Handler

By the android single thread model rule, we can not access UI elements (bitmap, text view, button, etc..) directly for another thread defined inside that activity. If you need to update the UI from any worker thread, you need to connect it with the main thread. To achieve this Android comes with the classes i.e. Handler or AsyncTask.

A Handler allows you to communicate back with the UI thread from other background thread. This is useful in android as android doesn’t allow other threads to communicate directly with UI thread.

How Handler Works

Screenshot 2019-09-07 21.50.13

Handler

There are two main uses for a Handler:

  1. To schedule messages and runnables to be executed at some point in the future.
  2. To enqueue an action to be performed on a different thread than your own.

There are two ways of communicating with the handler:

  1. Messages
  2. Runnable objects
Message

Defines a message containing a description and arbitrary data object that can be sent to a handler.

While the constructor of message is public, the best way to get one of these is to call Message.obtain() or one of the Handler obtainMessage methods which will pull them from the pool of recycled objects.

How to send Message objects?

sendMessage(): Puts the message on the queue immediately.

sendMessageAtFrontOfQueue(): Puts the message on the queue immediately and places it in front of the message queue so your message takes priority over all others.

sendmessageAtTime(): puts the message on the queue at the stated time, expressed in the form of milliseconds based on system uptime(Systemclock.uptimeMillis()).

sendMessageDelayed(): puts the message on the queue after a delay, expressed in milliseconds.

sendEmptyMessage(): sends an empty message object to the queue, allowing you to skip the obtainMessage() step.

To process these messages, Handler needs to implement handleMessage(), which will be called with each message that appears on the message queue. There the Handler can update the UI as needed.

Note sendMessage() can be called in any threads but the handler code (i.e handleMessage()) will always be running in the Thread which the Handler’s Looper resides in.

Now to understand the working of Thread Looper Handler when the task in the MessageQueue will be a message look at the below diagram:

Runnable

Runnable is an interface which contains one single method run() with no arguments. The post versions methods of Handler class accept the Runnable objects to be added to the message queue and the code written inside the run method will be executed by the thread to which this handler is attached.

How to send Runnable objects?

post(Runnable r): Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

postAtTime(Runnable r, long uptimeMillis): Causes the Runnable r to be added to the message queue, to be run at a specific time given by uptimeMillis.

postDelayed(Runnable r, long delayMillis): Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses.

In the above Thread Looper Handler diagram when you want to send a Runnable object from the background thread (Thread 1) to the main thread using the post method of the handler then it gets added in the message queue of the main thread and then it gets executed inside the thread to which handler is attached (the UI thread).

Handler Example

Now let’s take an example in which we are downloading an image over the network in an imageView on button click. In the below example we are communicating with handler using both message and Runnable object.

MainActivity.java

package trendlife.handlerdemo;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

import android.view.View;

import android.widget.ImageView;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;

import java.io.IOException;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;

public class MainActivity extends AppCompatActivity {

    ImageView imageView;

    Handler handler;

    ProgressBar progressBar;

    TextView tv_loading_image;

    Boolean progressStatus = false;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.image);

        tv_loading_image = findViewById(R.id.tv_loading);

        progressBar = findViewById(R.id.progressbar);

      //As we have created handler inside the UI thread so this handler get attached with the Looper,message queue of the UI thread.

        handler = new Handler() {

         //the code inside the handleMessage() run inside the main thread and handler execute the code and then update the UI.

            @Override

            public void handleMessage(Message msg) {

                progressStatus = false;

                Object obj = msg.getData().getParcelable("MyObject");

                imageView.setImageBitmap((Bitmap) obj);

                imageView.setVisibility(View.VISIBLE);

                Toast.makeText(getApplicationContext(), "Image downloaded", Toast.LENGTH_SHORT).show();

            }

        };

    }

   //this method is called on DownloadImage button click

    public void downloadImage(View view) {

        Log.i("Button", "Tapped");

        progressStatus = true;

        //background thread started

        DownloadImage downloadImage = new DownloadImage();

        new Thread(downloadImage).start();

    }

    class DownloadImage implements Runnable {

        @Override

        public void run() {

            URL url;

            HttpURLConnection httpURLConnection;

            Bitmap result = null;

            //communicating with handler using Runnable object

            handler.post(new Runnable() {

                @Override

                public void run() {

                    if (progressStatus = true) {

                        tv_loading_image.setText("Loading Image...");

                        tv_loading_image.setVisibility(View.VISIBLE);

                        progressBar.setVisibility(View.VISIBLE);

                    }

                }

            });

         //getting image bitmap

            try {

                url = new URL("https://vignette.wikia.nocookie.net/disney/images/0/0a/ElsaPose.png/revision/latest?cb=20170221004839");

                httpURLConnection = (HttpURLConnection) url.openConnection();

                httpURLConnection.connect();

                InputStream in = httpURLConnection.getInputStream();

                result = BitmapFactory.decodeStream(in);

            } catch (MalformedURLException e) {

                e.printStackTrace();

            } catch (IOException e) {

                e.printStackTrace();

            }

            //communicating with handler using Message object

            Message message = handler.obtainMessage();

            Bundle bundle = new Bundle();

            bundle.putParcelable("MyObject", result);

            message.setData(bundle);

            handler.sendMessage(message);

        }

    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">


    <TextView
        android:id="@+id/tv_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="Loading Image..."
        android:textColor="@color/colorAccent"
        android:textSize="20sp"
        android:textStyle="bold"
        android:visibility="invisible"/>

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginTop="10dp"
        android:visibility="invisible"
        android:gravity="center"
        android:layout_below="@+id/tv_loading"/>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:orientation="vertical">


        <ImageView
            android:id="@+id/image"
            android:layout_width="350dp"
            android:layout_height="350dp"
            android:background="@drawable/border_image"
            android:visibility="invisible" />


        <Button
            android:id="@+id/btn_download"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:background="@android:color/holo_blue_bright"
            android:onClick="downloadImage"
            android:padding="10dp"
            android:text="download image"
            android:textColor="@android:color/black"
            android:textStyle="bold" />

    </LinearLayout>


</RelativeLayout>

When you run the application HandlerDemo it will look like this as shown below:

I hope this article will help you in understanding what is Handler, why we use it, it’s working and its example.

Exit mobile version