This is the second part of my series of blog posts on Android non-UI thread-to-UI thread communications. See here for the start of the series.  As a refresher, this series of posts is about how non-UI threads can communicate back to the UI thread in an Android application in order to update the user interface.  Non-UI threads are not allowed to make updates to the UI.  Trying to do too much work (as defined as not allowing the user to interact with the UI for more than 5 seconds) on the UI thread leads to ANR errors.

The Simple App – review

In my last post, I provided a simple app (called Simple App) that provided two buttons to start/stop a non-UI thread.  The non-UI thread’s job is to simulate long running work was by generating a random number, call the UI to have a TextView widget update the display of the random number, and then sleep for a number of seconds.

simpleappdiag

In the first of this five part series, I showed you how to use an Activity’s runOnUiThread() method in a non-UI thread to post requests to change the user interface via the UI thread’s event message queue.  In this blog, option #2 is explained – using the post() method of an Android View component to request changes to the UI.

 

Option 2 – using View’s post() method

When a non-UI thread has access to a View component from the user interface, the non-UI thread can make a call to that View component’s post() method to request a UI change.

Just like when calling on runOnUiThread() of an Activity, calling on the View’s post() communicates the desire to request work be run on the UI thread by publishing a message in the event queue of the UI thread.  When it can, the UI thread picks up the action message in the event queue and performs the UI change.  So the  post() method is a convenience (just as runOnUiThread is) for completing this messaging operation.

Here is the non-UI thread class – DoSomethingThread from the SimpleApp – that generates a random number and then calls on its publishProgress() method to get the random number displayed on the UI using post().

public class DoSomethingThread extends Thread {

  private static final String TAG = "DoSomethingThread";
  private static final int DELAY = 5000; // 5 seconds
  private static final int RANDOM_MULTIPLIER = 10;

  @Override
  public void run() {
    Log.v(TAG, "doing work in Random Number Thread");
    while (true) {
      int randNum = (int) (Math.random() * RANDOM_MULTIPLIER);
      publishProgress(randNum);
      try {
        Thread.sleep(DELAY);
      } catch (InterruptedException e) {
        Log.v(TAG, "Interrupting and stopping the Random Number Thread");
        return;
      }
    }
  }

  private void publishProgress(int randNum) {
    Log.v(TAG, "reporting back from the Random Number Thread");
    final String text = String.format(getString(R.string.service_msg), randNum);
    mainFrag.resultsTextView.post(new Runnable() {
      @Override
      public void run() {
        mainFrag.getResultsTextView().setText(text);
      }
    });
  }
}

Note in line 3 of the publishProgress() method above in the one line of code that changes between Option 1 (using runOnUiThread) and Option 2 here (using post).

Considerations of Option 2 – post() method

As indicated, the post() method is using the same event message queue under the covers as runOnUiThread().  So in some regards, many of the pro/cons of post() are that of runOnUiThread().  A StackOverflow post (here) provides some detailed insight.

Essentially, in order to use post(), your non-UI thread must have awareness of a View component (from the UI).  This allows the non-UI thread to avoid direct connection to the Activity (which was required with runOnUiThread).  There are times when your non-UI thread may know a View and not an Activity or vice versa.  However, both options might more tightly couple the non-UI thread to the UI side given View components and Activities are UI “stuff.”

Also as with the runOnUiThread() option, this post() method option requires you to create and manage your threads more directly – and thereby have more control of the thread and its communication but also require you to have more experience with Java concurrency/thread APIs and issues.

Unlike the runOnUiThread() method, the post() method does not check whether the current thread is the UI thread.  Therefore the post() method does not cause the Runnable to execute immediately if it is on the UI thread.  Instead, post() always has an event message pushed to the message queue for reaction by the UI thread.

 


ALL FIVE ARTICLES IN SERIES: Android Non-UI to UI THread Communication