Multi-threading in Android

February 6, 2016

Present daily-use devices (mobiles, tablets, smartwatches) run on multi-core CPUs. Application developers can utilize this additional processing power and create products that were technically not feasible few years back. Multi-threading programming models are very useful in this context. To be able to effectively put multi-threading to use, we have to understand the highs and lows of this programming model. In this post we talk about multi-threaded programming in context of the Android platform.

Android Single Thread Model

Generally, too many threads introduce execution delays resulting from context switching from one thread to another. To mitigate this, when an Android application starts, a new Linux process is started with a single thread of execution called the main thread. This is responsible for taking care of all the UI related event handling and is popularly known as the UI Thread. So if we want to set the text of a TextView, the UI thread is the one changing the view for us – this is known as the single thread model.

mUIThread1

Fig 1. mUiThread – Thread created for the main process in Android Studio Debug Window

There is a sane reason for sticking to this strict design philosophy. Apart from the overhead of context switching between threads, indiscriminate use of multiple threads pose a variety of synchronization problems leading to race conditions and deadlocks (we will talk about it in a later post).

On the other hand, doing CPU-intensive tasks (functions that take a lot of time to complete) on the UI thread will render it busy and it will be unable to process drawing events and user inputs. If the UI thread is blocked for more than a few seconds, the application becomes non-responsive and Android displays the notorious “Application Not Responding” (ANR) dialog – not good in terms of user experience. So, it is important to remember the golden words: “DO NOT BLOCK THE UI THREAD”. This presents us with just the right opportunity for putting the multi-threaded programming model to use.

In this post, we will create a clock that displays the current time in form of Hour:Minute:Second with a start and stop feature. Creating a clock requires refreshing the view every second and if done on the UI thread will result in slow performance. To achieve this we will start a worker thread that will create a timer object and update the UI every second. We will keep the GUI of the app simple and mainly focus on the threading and worker thread to UI thread communication.

app UI

Fig 2. The Application UI

As you can see that there are two buttons that have the Onclick function set as clickStart() and clickStop(). The intention is to start the clock when the user clicks on Start button and stop the clock on clicking the Stop button. OK, let’s gear up to go a little deeper into thread architecture.

Threading: Under the hood

On Android, each thread executes its “run” function exactly once. Once the function returns the thread terminates. If we want our thread to remain active and process multiple requests we would require two things – first, the ability to run indefinitely and second, a mechanism to receive requests. A MessageQueue fulfills the second requirement. It stores messages which our thread should process. The first requirement is met through a Looper class. The Looper.loop() method allows the thread to run forever and process messages that have been posted to its queue. The MessageQueue object associated with a thread can be obtained using Looper.myQueue(). Messages can be sent to the queue through a Handler object.

Now that we understand how a thread can live indefinitely and process messages, it should come as no surprise that our UI thread is one such candidate and has a MesssageQueue associated with it. Whenever there is a change in the UI, such as changes to the state of a radio button or the text within an EditView etc., an event is fired. As a result, messages (requesting view redraws) are posted to the UI thread’s message queue which are subsequently handled by the UI thread. Thus, in the Single Thread Model, all UI modifications are performed by the UI thread. If the call to update the UI is from any thread other than UI thread an exception is thrown “CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views”. Alas, the worker thread cannot directly redraw the UI but can only send a request to the UI thread to perform the necessary action.

Though this seems a bit limiting, there is nothing to worry. Android offers various ways to interact with the UI thread from other threads –

    1. Handler
    2. runOnUiThread(Runnable)
    3. View.post()

Lets implement these alternatives one by one.

1. Handler: handling UI updation woes…

Handler instance can be created to send requests to UI thread. A Handler instance is associated with a thread and its message queue. When you create a new Handler, it is bound to the message queue of the thread that is creating it and will deliver messages and runnables to that message queue and execute them as they are dequeued from the head of the message queue.

msgq

Fig 3. Interaction between Handlers, Message Queue and Looper

The Handler object that can communicate with the UI thread should be created outside the run method of the worker thread and the worker thread should have a reference to the Handler object. Handler handler = new Handler()); Or a handler object associated with UI thread can be safely created anywhere with the following parameters:

 Handler handler = new Handler(Looper.getMainLooper());

To update the UI, there are two common ways how a handler can be used:

  1. Handler instance can be used to send messages and handle messages. A Message object contains a description and arbitrary data object that can be sent to the handler. The best way to create a Message object is to call Message.obtain() that returns a Message from the global message pool or by using one of the Handler.obtainMessage() methods of Handler class. The commonly used functions for sending a message are:

messagefunction

The Message will be processed by Handler’s handleMessage(Message), in the thread attached to this handler. So you need to provide an implementation of this function.

Following code snippet updates the time using a Handler instance and sending Message to the UI MessageQueue. Message object is set to a User class TimeManager. Note, the implementation provided for the handleMessage function.

class MessageHandlerClass extends Thread
{
    handlerTime = new Handler()
    {
        public void handleMessage(Message msg)
        {
            TimeManager tm = (TimeManager)msg.obj;
            hr.setText(String.valueOf(tm.getHour()));
            min.setText(String.valueOf(tm.getMinute()));
            sec.setText(String.valueOf(tm.getSecond()));

        }
    };

    public void run()
    {
        while(!stopThread)
        {
            try
            {
                Message msg = test.obtainMessage();
                Calendar cal = Calendar.getInstance();

                int second = cal.get(Calendar.SECOND);
                int minute = cal.get(Calendar.MINUTE);

                int hour = cal.get(Calendar.HOUR);

                TimeManager tm = new TimeManager(hour,minute, second);
                msg.obj = (TimeManager)tm;
                handlerTime.sendMessage(msg);

                sleep(1000);
            }
            catch(InterruptedException ie)
            {
                ie.printStackTrace();
            }
        }
    }
}

class TimeManager
{
    int hour;
    int minute;
    int second;

    TimeManager(int hr, int min, int sec)
    {
        hour = hr;
        minute = min;
        second = sec;
    }

    int getHour()
    {
        return hour;
    }

    int getMinute()
    {
        return minute;
    }

    int getSecond()
    {
        return second;
    }
}

2. Alternatively, a Handler instance can be used to post Runnable objects to the UI thread’s Message Queue. The commonly used functions for posting a Runnable object are:

runnablefunctions

Following code snippet uses a handler.post method to post a runnable in the UI thread’s Message Queue.

 

class HandlerClass extends Thread
{
    public void run()
    {
        try
        {
            while(!stopThread)
            {
                handler.post(new Runnable()
                        {
                        public void run()
                        {
                        Calendar cal = Calendar.getInstance();
                        int second = cal.get(Calendar.SECOND);
                        int minute = cal.get(Calendar.MINUTE);
                        int hour = cal.get(Calendar.HOUR);
                        hr.setText(String.valueOf(hour));
                        min.setText(String.valueOf(minute));
                        sec.setText(String.valueOf(second));
                        }
                        });
                sleep(1000);
            }
        }
        catch (Exception ie)
        {
            ie.printStackTrace();
        }
    }
}

2. runOnUiThread(Runnable message)

This function can be called with appropriate runnable to execute the action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread. The neatest way to use runOnUiThread is to create a function that calls runOnUiThread. This function is then called from the worker thread to get the actual job done.

void callUIMod()
{
    runOnUiThread( 
        new Runnable() { 
            @Override public void run()
            {
                Calendar cal = Calendar.getInstance();
                int second = cal.get(Calendar.SECOND);
                int minute = cal.get(Calendar.MINUTE);
                int hour = cal.get(Calendar.HOUR);
                hr.setText(String.valueOf(String.valueOf(hour)));
                min.setText(String.valueOf(String.valueOf(minute)));
                sec.setText(String.valueOf(String.valueOf(second)));
            }
        }
    );
}

Now call this function from the worker thread’s run method as shown below

class WorkerClass extends Thread
{
    public void run()
    {
        while(!stopThread)
        {
            try
            {
                callUIMod();
                sleep(1000);
            }
            catch(InterruptedException ie)
            {
                ie.printStackTrace();
            }
        }
    }
}

Observe that the sleep is called in the worker thread and not in the runnable. If sleep is called in runnable then the main UI thread sleeps and the UI is not updated per second.

3. View.post()

Let’s have a look into the post method of a View instance. The post() method of view class can be used to send the invalidate request from the view to the UI thread. The invalidate request means that the data/state of the view that is already drawn is no longer valid and hence it it needs to be redrawn at some point in the future. To use this method, we need the reference to the view. Internally, the view.post() call is directed to Handler’s getPostMessage is called  that initializes a Message object msg. and  the runnable passed in the View.post method is set as message object callback function.

class ViewPostClass extends Thread
{
    public void run()
    {
        try
        {
            while(!stopThread)
            {
                hr.post(new Runnable()
                        {
                            public void run()
                {
                    Calendar cal = Calendar.getInstance();
                    int second = cal.get(Calendar.SECOND);
                    int minute = cal.get(Calendar.MINUTE);
                    int hour = cal.get(Calendar.HOUR);
                    hr.setText(String.valueOf(hour));
                    min.setText(String.valueOf(minute));
                    sec.setText(String.valueOf(second));
                }
                });
                sleep(1000);
            }
        }
        catch(Exception ie )
        {
            ie.printStackTrace();
        }
    }
}

Its important to note that both runOnUiThread and View.post post a runnable to a Handler associated with the UI Thread. Both of these methods have the same functionality except for a small difference. The runOnUiThread method checks the thread and if it is the  UI thread the runnable is executed immediately else the request is posted at the end of MessageQueue. In case of View.post, the request is always posted at the end of MessageQueue. The method View.postDelayed takes as the second parameter the time in milliseconds and causes the Runnable to be added to the message queue, to be run after the specified amount of time elapses.

The code for Start and Stop button is written as

public void clickStart(View v)
{
    //Reinitialize the boolean variable to false
    stopThread = false;
    //Create the object of the worker thread class
    //Start the worker thread
    mhcObject.start();
    start.setEnabled(false);
}

public void clickStop(View v)
{
    if(start.isEnabled() == false)
    {
        stopThread = true;
    }
    start.setEnabled(true);
}
Note: The use of a boolean variable stopThread to stop the thread. Since the method Thread.stop() is deprecated, this variable maintain the status of the worker thread. The while loop in the run() method of the worker thread exits when this variable is set to true.