Basics of multi-threading in Android Mar 20, 2014

About This Document

This document is a technical article which describes the ways to implement multi-threading in Android apps. This document is intended for developers with a basic knowledge of Java language and the Android SDK. To better understand contents of this article please download the related example application from http://developer.samsung.com.
The provided application shows background threads in action, furthermore a Wi-Fi connection between two devices is used to demonstrate how easy is to write a simple chat app.

Introduction

Back in 2009 when the first Samsung Android powered smart phones appeared on the market it was a revolution in multitasking on the mobile device. Customers were able to run multiple apps at the same time, but in fact all of them were processed by a single core of the processor, because the processors had only one core, leading to potential performance issues. Now we have quad-core CPU’s like the Exynos 4412 used in the Samsung Galaxy Note II, so real multitasking is now available. From the user’s point of view, performance has improved while for the developer these changes have a very significant impact. We will discuss the pros and cons of multi-threading and familiarize ourselves with specific solutions on the Android platform, which unlock ease of use concurrent apps development.

Android UI toolkit

You may already know that Android is a Linux based operating system, so it uses processes and thread management models to manage running apps, services and the other elements of the system. In fact a simple app is one running on a single process with a single thread of execution. The single thread is generally called the “main thread” or the “UI thread”, and we will be using these naming conventions in this document.
Despite the number of the cores your device has, the apps run on a single main thread. It means every long-running operation such as database initialization or heavy calculation blocks the UI thread. It causes the app to seem slow and the response time for input events delayed – in other words your app results in having serious performance problems.

[Image 1] Unresponsive Application dialogue [Image 1] Unresponsive Application dialogue

As a result of performing long operations on the UI thread the apps’ user may notice an awful user experience when using your app. As a consequence, you will probably receive low scores and negative comments on the Samsung Apps store reviews. The worst thing is ANR – Application Not Responding. This dialog may be shown in two situations:

  • No response for user input events for 5 seconds

  • BroadcastReceiver didn’t finish execution in 10 seconds

The user is prompted to close your app or to wait. It is not obvious what happened in this situation –either the operation will end successfully or a serious problem occurred. This in fact means that your app isn’t written too well so most people will close it. It is advised to test for this on multiple devices, both flagship and economy handsets. If you don’t encounter this situation on a flagship device, you may run into it on the cheaper one, which has less processing power. The solution for all of these problems, are background threads. Below are examples of the operations which should be carried out on separate threads.

  • Networking

  • Database operations

  • Heavy calculations

  • Object’s long initialization

Since API level 14 you will get a NetworkOnMainThreadException exception when performing networking operation on the UI thread. Later in this article we will discuss how to create different kinds of the background workers and perform operations without blocking the main thread.

UI modification

Modification of the user interface from the background threads is easy when you follow one vital rule – only the main thread may modify the UI. This does not mean you cannot modify the UI from the background thread, it just means that you have to do it in an appropriate way. Here is a simple example showing what may happen when you do not obey the rule.

public void onClick(final View v) {

  new Thread(new Runnable() {

    @Override
    public void run() {
      v.invalidate();
    }
  }).start();
}
[Code 1] Invalidate from a background thread

On the above code snippet you can see the onClick method, which will be called when any view has been pressed. All this does is invalidate the view which called the method, but from the non-main thread. It will end in an application crash and a stack trace like this will be shown on the Logcat console. The message of the exception describes the problem directly.

CalledFromWrongThreadException: 
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4891)
android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:990)
android.view.ViewGroup.invalidateChild(ViewGroup.java:4127)
android.view.View.invalidate(View.java:10374)
android.view.View.invalidate(View.java:10329)
com.sprc.multithreading.activity.MenuActivity$2.run(MenuActivity.java:55)
java.lang.Thread.run(Thread.java:856)
}
[Code 2] The stack trace

The solution in this case is very simple, the invalidate method’s javadoc states that it “must be called from a UI thread. To call from a non-UI thread, call postInvalidate”. The View class provides thread-safe methods to modify the UI. If you have a reference to a view you can simply pass a Runnable object to the message queue connected with the main thread. Here are the 3 most useful methods. For more, please refer to the View class’s javadoc.

  • public boolean post (Runnable action)

  • public boolean postDelayed (Runnable action, long delayMillis)

  • public void postOnAnimation (Runnable action)

Notice that the Activity class also has one method, which allows the performance of some unit of work which modifies the UI on the main thread. This method is called runOnUiThread and takes as an argument, the Runnable object, similar to the View class’s methods.

To call the methods mentioned above, you must have a reference to the View or Activity object in the other thread. This is normal when the thread is in the inner class of the activity, but in most cases programmers prefer to separate the code into its logical parts. In this case you can always pass a view/activity reference through the constructor, to any other class instance but it isn’t the best idea, because most of the methods from the views should then be public which violates good programming principles (i.e. encapsulation). Thankfully the Android API provides a Handler class to allow passing a Message object to the MessageQueue queue, so explicit references aren’t needed. The Handler class will be discussed in a separated topic, but first we will familiarize ourselves with basics of the Thread class providing the possibility to create a new thread.

Multi-threading
Thread

The java.lang.Thread class is available in the Java’s JDK since version 1.0, providing methods to start and to manage multiple threads running concurrently. The Thread implements a Runnable interface that has only one method to implement named run. The method returns nothing (void) and throws no exceptions. When starting a new thread by calling start on a thread instance, the run method will be called in a separated thread of execution - this is how multi-threading works. It’s very important to not call the run method directly, because a new thread will not be created and the run’s method body will be executed on the current thread. Let’s see three different implementations of the Runnable interface.

public class SecondThread extends OtherClass implements Runnable {

  @Override
  public void run() {
    // operations to be performed on a background thread
  }
    
}

new Thread(new SecondThread()).start();
[Code 3] The SecondThread implements the Runnable interface
new Thread(new Runnable() {

  @Override
  public void run() {
    // operations to be performed on a background thread
  }

}).start();
[Code 4] The Runnable implementation as an anonymous class
public class SecondThread extends Thread {

  @Override
  public void run() {
    // operations to be performed on a background thread
  }
} 

new SecondThread().start();
[Code 5] The SecondThread extends the Threads class

Implementing the Runnable interface directly, like in the first code snippet gives the benefit of polymorphism. The SecondThread could extend the OtherClass which is not possible when extending a Thread class directly like in the third example - because the multiple inheritances of classes are not allowed in Java. The code in example 4 shows the Runnable interface implementation as an anonymous class. You don’t have to declare a new class, but the code is not reusable. As with many things in life, the method you choose will depend on the context of use.

The android.os package

After a quick introduction to multi-threading in Java, we will look at a specific solution available on the Android platform. The classes from the android.os package were introduced, among others, in order to boost concurrency oriented development for Android, so it’s in your interest to familiarize yourself with them. They allow you to avoid reinventing the wheel, writing tons of boilerplate code to implement simple communication between the main and background threads.

Handler

The Handler class is the primary element of multi-thread communication. It allows sending Message and Runnable instances from one thread to another - not just the background to the main. Each Handler object is associated with a single thread and its message queue (MessageQueue). When you create a handler instance it’s automatically linked to the Looper of the thread, which calls the handler’s constructor, unless a custom Looper object has been specified. It means when a ‘new Handler()’ line of code is performed inside say, the onCreate callback of an activity, it will link the handler to the main thread. The picture below shows how this works.

 Hand movements recognized by the gesture sensor Figure 1: Hand movements recognized by the gesture sensor

Following example shows how to create a handler associated with the UI thread.

public class ChatActivity extends Activity {

  private Handler mUiHandler;
  private Handler mBackgroundHandler;

  private final Callback mCallback = new Callback() {

    @Override
    public boolean handleMessage(Message msg) {
      switch (msg.what) {
      case NetHandlerThread.ON_CONNECT:
        onConnect();
        break;
      case NetHandlerThread.ON_ERROR:
        onError((String) msg.obj);
        break;
      case NetHandlerThread.ON_DISCONNECT:
        onDisconnect();
        break;
      case NetHandlerThread.ON_RECEIVE_CHAT_MESSAGE:
        receiveMessage((ChatMessage) msg.obj);
        break;
      default:
        throw new IllegalArgumentException(Integer.toString(msg.what));
      }
      return true;
    }
  };


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chat_activity);
    
    mUiHandler = new Handler(mCallback);

    if (mServerMode) {
      mHandlerThread = new Server(mUiHandler);
      showProgressDialog(serverIP);
    } else  {
      if (inetAddress != null) {
        mHandlerThread = new Client(mUiHandler, inetAddress);
      } else {
        onError(getString(R.string.connect_error));
      }
    }

    mHandlerThread.start();
    mBackgroundHandler = new NetHandlerThread.SendHandler(mHandlerThread);
  }
}
[Code 6] Two handlers associated with different threads

At the beginning, the two Handler references are declared, with the handler’s callback implementation being used to distinguish what message has been received afterwards. The mUiHandler is initialized in the onCreate callback and the callback object is passed as an argument. The handler has a ‘UI’ in the name because it is associated with the main thread. The second handler reference is named ‘mBackgroundThread’. This is the SendHandler class instance, which is defined as an inner class inside the NetHandlerThread. The background handler is associated with the NetHandlerThread which is our client or server thread. This will result in two handlers connected to a different threads being created. Now simple thread-to-thread communication is possible.

public static class SendHandler extends Handler {

  private final WeakReference<NetHandlerThread> mReference;

  public SendHandler(NetHandlerThread netHandlerThread) {
    super(netHandlerThread.getLooper());
    mReference = new WeakReference<NetHandlerThread>(netHandlerThread);
  }

  @Override
  public void handleMessage(Message msg) {
    NetHandlerThread reference = mReference.get();

    switch (msg.what) {
    case ON_SEND_CHAT_MESSAGE:
      if (reference != null) {
        reference.sendMessage((ChatMessage) msg.obj);
      }
      break;
    default:
      throw new IllegalArgumentException();
    }
  }
}
[Code 7] The SendHandler inner class implementation

The SendHandler implementation looks different to the UI one. As with threads we have several ways to achieve the same result, so different implementation has been shown in the sample app. Inside the constructor the super method is called, which in fact is the Handler(Looper looper) constructor. The looper instance obtained from the handler thread is passed as an argument, which in effect connects the handler with the handler thread’s looper. Next follows the handleMessage method implementation, similar to the one from previous code example, but only one message is handled.

At this point it is possible to send ON_SEND_CHAT_MESSAGE event to the background thread and four other events in the opposite direction. The int value assigned to the message’s what variable, points to which one of the events has been received. Here is how the message from the ChatActivity is passed to the send handler.

private void sendMessage() {
  final String text = mInputMessage.getText().toString();

    if (!text.isEmpty()) {
      mInputMessage.setText("");

      ChatMessage chatMessage = ChatMessage.obtain(text, MessageOwner.YOU);
      mMessageAdapter.addMessage(chatMessage);
      ChatMessage chatMesssageToSend = ChatMessage.obtain(chatMessage);
      chatMesssageToSend.changeOwner();

      Message message = Message.obtain(null, NetHandlerThread.ON_SEND_CHAT_MESSAGE, chatMesssageToSend);
      mBackgroundHandler.sendMessage(message);
    }
  }
[Code 8] Create and send a chat message to the background thread

The Receiver class is responsible for reading data from the input stream and sending it to the ChatActivity via the UI handler. The implementation of the run method is as follows.

@Override
public void run() {
  while (!Thread.interrupted()) {
    final Object message;

    try {
      message = mObjectInputStream.readObject();
    } catch (Exception e) {
      onError("Disconnected");
      return;
    }

    mUiHandler.sendMessage(Message.obtain(null, NetHandlerThread.ON_RECEIVE_CHAT_MESSAGE, message));
  }
}

void onError(String message) {
  mUiHandler.sendMessage(Message.obtain(null, NetHandlerThread.ON_ERROR, message));
}
[Code 9] The receiver’s run method implementation

If an error occurred during reading from the stream, the onError method is called and the execution of the runnable terminates. The chat activity is informed about the error via the UI handler.

HandlerThread

Implementation of the background handler described in the previous section has taken as an argument the NetHandlerThread instance. The NetHandlerThread is a subclass of the HandlerThread class, which in fact is a thread that has a Looper. You can always create your own Thread subclass and insatiate a Looper, but the HandlerThread is a time-saving ready for use implementation, so it is strongly recommended to rely on it.

public abstract class NetHandlerThread extends HandlerThread {

  NetHandlerThread(String name, Handler uiHandler) {
    super(name);
    mUiHandler = uiHandler;
    mExecutorService = Executors.newSingleThreadExecutor();
  }

  @Override
  protected void onLooperPrepared() {
    onInitializeStreams();
    startReceiver();
    super.onLooperPrepared();
  }

  private void startReceiver() {
    mReceiver = new Receiver(mObjectInputStream, mUiHandler);
    mExecutorService.execute(mReceiver);
  }

  private void sendMessage(ChatMessage message) {
    try {
      mObjectOutputStream.writeObject(message);
      mObjectOutputStream.flush();
    } catch (IOException e) {
      onError(e.getMessage());
    }
  }
}
[Code 10] The NetHandlerThread implementation

Starting from the constructor the name for the thread handler is set. It is mostly useful for debugging purposes, because it is much easier to debug threads when they have meaningful names. Inside the onLoopPrepared callback the streams are initialized and the receiver is started on a single thread executor service.

The thread in fact does nothing, besides waiting and occasionally performing some networking operations, just like the receiver. The communication is fully asynchronous. The handler thread is blocked at the message queue. When the user types in a message, the chat activity sends it to the SendHandler which means that the message is being added to the message queue of the handler thread. Now the net handler thread is woken up to handle the message. In this scenario the sendMessage method is called. The ChateMessage object is written to the output stream and then the data is flushed to the other end of the socket – to the stranger with whom you are now chatting. The handler thread is put to sleep if no other messages are waiting in the queue.

Summarizing the HandlerThread class helped us to create easy and robust asynchronous communication between two devices, without writing any redundant lines of code.

AsyncTask

The additional part of the chat application consists of two buttons, named ‘Generate numbers’ and ‘The greatest value’. The first one generates a specified number of the double values and returns it as an array. The code responsible for this work is placed inside the GenerateTask class. The second button finds the greatest number in the previously generated array and the code is placed in the FindTask class. What connects these two classes is that they both are subclasses of the AsyncTask and are meant to simulate heavy calculations. In fact generating even a large number of double values isn’t too heavy, so 2 seconds sleep was added to simulate the long operation circumstances.

As was said at the beginning of the article, any heavy calculations should be performed on a background rather than the main thread, because blocking the UI thread may result in performance issues. Asynchronous tasks are very handy when a large job has to be done. The AsyncTask has only one method you are obliged to implement, which is processed in the background and is named doInBackground. The rest of the methods run on the UI thread and the class is parameterized with three types:

  • Params - type of the input parameters

  • Progress - type of the progress’s unit

  • Result - type of the calculations’ result

The GenerateTask takes as a parameter reference to an array of double values. It does not publish any progress so the second parameter is Void. The generated values are assigned to the array cells , while Void is also a type of the result.

public class GenerateTask extends AsyncTask<double[], Void, Void> {

  @Override
  protected void onPreExecute() {
    mGenerateButton.setEnabled(false);
    mGenerateProgress.setVisibility(View.VISIBLE);
    super.onPreExecute();
  }

  @Override
  protected void onPostExecute(Void result) {
    mGenerateProgress.setVisibility(View.INVISIBLE);
    mFindButton.setEnabled(true);
    super.onPostExecute(result);
  }

  @Override
  protected Void doInBackground(double[]... params) {
    mNumbers = params[0];
    Random random = new Random();

    for (int i = 0; i < mNumbers.length; ++i) {
      mNumbers[i] = random.nextDouble() * 100.0f;
    }

    SystemClock.sleep(2000);
    return null;
  }

  @Override
  protected void onCancelled(Void result) {
    mGenerateProgress.setVisibility(View.INVISIBLE);
    mGenerateButton.setEnabled(true);
    Arrays.fill(mNumbers, 0.0f);
    super.onCancelled(result);
  }

}
[Code 11] The GenerateTask implementation

The generate task implementation should look like the above. The heavy job is done in the doInBackground method and the view’s modification is performed in other methods which run on the UI thread. The order of method’s called, is as follows:

  • onPreExecute

  • doInBackground

  • onProgressUpdate

  • onPostExecute

The onProgressUpdate method is invoked after a call of the publishProgress method. Usage of this method is shown in the FindTask code below.

At the end, the onCancelled callback is implemented. This is called when cancel is called on the AsyncTask object.

The code of the find task utilizes the onProgressUpdate method. We know the exact size of the provided array, so it is easy to calculate what the progress of work is.

public class FindTask extends AsyncTask<double[], Integer, Double> {

  @Override
  protected void onPreExecute() {
    mFindButton.setEnabled(false);
    mFindProgress.setVisibility(View.VISIBLE);
    super.onPreExecute();
  }

  @Override
  protected void onPostExecute(Double result) {
    mGenerateButton.setEnabled(true);
    mFindProgress.setVisibility(View.INVISIBLE);
    Toast.makeText(mContext, Double.toString(result), Toast.LENGTH_LONG).show();
    super.onPostExecute(result);
  }

  @Override
  protected Double doInBackground(double[]... params) {
    double[] numbers = params[0];
    double result = double.MIN_VALUE;

    for (int i = 0; i < numbers.length; ++i) {
      if (i % 20 == 0) {
        publishProgress(i);
      }

      if (numbers[i] > result) {
        result = numbers[i];
      }
    }

    return result;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
    mFindProgress.setProgress(values[0]);
    super.onProgressUpdate(values);
  }

  @Override
  protected void onCancelled(Double result) {
    mFindProgress.setVisibility(View.INVISIBLE);
    mFindButton.setEnabled(true);
    super.onCancelled(result);
  }

}
[Code 12] The GenerateTask implementation

The publishProgress method is called with an iterator value, because the length of the progress bar was set to the size of the array via the setMax method available in the ProgressBar class. If the array is very big the progress publishing may take more time than the calculations. Here in the code, it is published every 20 checked values. It costs a lot of views to invalidate and only increases the time spent on the calculations. You may take this as an example of how to not do it. Always consider publishing the progress in a small but sufficient number of times. At the end of calculation process the onPostExecute method announces the greater found number as a toast message and the task ends its execution.

In the documentation a kind of warning is written for the execute method, because depending on the Android version the implementation may vary.

Note

this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting HONEYCOMB, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution. If you truly want parallel execution, you can use the executeOnExecutor(Executor, Params...) version of this method with HREAD_POOL_EXECUTOR; however, see commentary there for warnings on its use.”
Source: http://developer.android.com/reference/android/os/AsyncTask.html

The AsyncTask class lets you perform some background work without creating threads or handlers. It is very nice for developers because is it probably the easiest way so far to perform background operations, but the async task should not be used when you need very long running workers such as for networking, where you should use Services or HandlerThreads for example.

Summary

This article in brief described the Android UI toolkit, the Thread class and three of the important classes of the android.os package, mostly useful when creating multi-threaded apps. Utilizing the background threads may accelerate your apps development and make the most of the device possibilities, but it may cost you more complicated code and sometimes thread synchronization. Bear this in mind when developing an Android app because it might end up saving you a lot of time.