Dealing with Threads

Users like snappy applications. Users do not like applications that feel sluggish.

The way to help your application feel snappy is to use the standard threading capabilities built into Android. This chapter will go through the issues involved with thread management in Android and will walk you through some of the options for keeping the user interface crisp and responsive.

The Main Application Thread

When you call setText() on a TextView, you probably think that the screen is updated with the text you supply, right then and there.

You would be mistaken.

Rather, everything that modifies the widget-based UI goes through a message queue. Calls to setText() do not update the screen — they just place a message on a queue telling the operating system to update the screen. The operating system pops these messages off of this queue and does what the messages require.

The queue is processed by one thread, variously called the “main application thread” and the “UI thread”. So long as that thread can keep processing messages, the screen will update, user input will be handled, and so on.

However, the main application thread is also used for nearly all callbacks into your activity. Your onCreate(), onClick(), onListItemClick(), and similar methods are all called on the main application thread. While your code is executing in these methods, Android is not processing messages on the queue, and so the screen does not update, user input is not handled, and so on.

This, of course, is bad. So bad, that if you take more than a few seconds to do work on the main application thread, Android may display the dreaded “Application Not Responding” dialog (ANR for short), and your activity may be killed off.

Nowadays, though, the bigger concern is jank.

“Jank”, as used in Android, refers to sluggish UI updates, particularly when something is animating. For example, you may have encountered some apps that when you scroll a ListView in the app, the ListView does not scroll smoothly. Rather, it scrolls jerkily, interleaving periods of rapid movement with periods where the animation is frozen. Most of the time, this is caused by the app’s author doing too much work on the main application thread.

Android 4.1 introduced “Project Butter”, which, among other things, established a baseline for “doing too much work on the main application thread”. We will “drop frames” if we take more than ~16ms per frame (60 frames per second), and dropped frames are the source of jank. Since we may be called many times during a frame, each of our callbacks needs to be very cheap, ideally below 1ms. We will get much more into the issue of jank later in the book, but it is important to understand now that any significant delay in the execution of our code on the main application thread can have visible effects to the user.

Hence, you want to make sure that all of your work on the main application thread happens quickly. This means that anything slow should be done in a background thread, so as not to tie up the main application thread. This includes things like:

  1. Internet access, such as sending data to a Web service or downloading an image
  2. Significant file operations, since flash storage can be remarkably slow at times
  3. Any sort of complex calculations

Fortunately, Android supports threads using the standard Thread class from Java, plus all of the wrappers and control structures you would expect, such as the java.util.concurrent class package.

However, there is one big limitation: you cannot modify the UI from a background thread. You can only modify the UI from the main application thread. If you call setText() on a TextView from a background thread, your application will crash, with an exception indicating that you are trying to modify the UI from a “non-UI thread” (i.e., a thread other than the main application thread).

This is a pain.

Getting to the Background

Hence, you need to get long-running work moved into background threads, but those threads need to do something to arrange to update the UI using the main application thread.

There are various facilities in Android for helping with this.

Some are high-level frameworks for addressing this issue for major functional areas. One example of this is the Loader framework for retrieving information from databases, and we will examine this in a later chapter.

Sometimes, there are asynchronous options built into other Android operations. For example, when we discuss SharedPreferences in a later chapter, we will see that we can persist changes to those preferences synchronously or asynchronously.

And, there are a handful of low-level solutions for solving this problem, ones that you can apply for your own custom business logic.

Asyncing Feeling

One popular approach for handling this threading problem is to use AsyncTask. With AsyncTask, Android will handle all of the chores of coordinating separate work done on a background thread versus on the UI thread. Moreover, Android itself allocates and removes that background thread. And, it maintains a small work queue, further accentuating the “fire and forget” feel to AsyncTask.

The Theory

Theodore Levitt is quoted as saying, with respect to marketing: “People don’t want to buy a quarter-inch drill, they want a quarter-inch hole”. Hardware stores cannot sell holes, so they sell the next-best thing: devices (drills and drill bits) that make creating holes easy.

Similarly, many Android developers who have struggled with background thread management do not want background threads — they want work to be done off the UI thread, to avoid jank. And while Android cannot magically cause work to not consume UI thread time, Android can offer things that make such background operations easier and more transparent. AsyncTask is one such example.

To use AsyncTask, you must:

  1. Create a subclass of AsyncTask
  2. Override one or more AsyncTask methods to accomplish the background work, plus whatever work associated with the task that needs to be done on the UI thread (e.g., update progress)
  3. When needed, create an instance of the AsyncTask subclass and call execute() to have it begin doing its work

What you do not have to do is:

  1. Create your own background thread
  2. Terminate that background thread at an appropriate time
  3. Call all sorts of methods to arrange for bits of processing to be done on the UI thread

AsyncTask, Generics, and Varargs

Creating a subclass of AsyncTask is not quite as easy as, say, implementing the Runnable interface. AsyncTask uses generics, and so you need to specify three data types:

  1. The type of information that is needed to process the task (e.g., URLs to download)
  2. The type of information that is passed within the task to indicate progress
  3. The type of information that is passed when the task is completed to the post-task code

What makes this all the more confusing is that the first two data types are actually used as varargs, meaning that an array of these types is used within your AsyncTask subclass.

This should become clearer as we work our way towards an example.

The Stages of AsyncTask

There are four methods you can override in AsyncTask to accomplish your ends.

The one you must override, for the task class to be useful, is doInBackground(). This will be called by AsyncTask on a background thread. It can run as long as it needs to in order to accomplish whatever work needs to be done for this specific task. Note, though, that tasks are meant to be finite – using AsyncTask for an infinite loop is not recommended.

The doInBackground() method will receive, as parameters, a varargs array of the first of the three data types listed above — the data needed to process the task. So, if your task’s mission is to download a collection of URLs, doInBackground() will receive those URLs to process.

The doInBackground() method must return a value of the third data type listed above — the result of the background work.

You may wish to override onPreExecute(). This method is called, from the UI thread, before the background thread executes doInBackground(). Here, you might initialize a ProgressBar or otherwise indicate that background work is commencing.

Also, you may wish to override onPostExecute(). This method is called, from the UI thread, after doInBackground() completes. It receives, as a parameter, the value returned by doInBackground() (e.g., success or failure flag). Here, you might dismiss the ProgressBar and make use of the work done in the background, such as updating the contents of a list.

In addition, you may wish to override onProgressUpdate(). If doInBackground() calls the task’s publishProgress() method, the object(s) passed to that method are provided to onProgressUpdate(), but in the UI thread. That way, onProgressUpdate() can alert the user as to the progress that has been made on the background work. The onProgressUpdate() method will receive a varargs of the second data type from the above list — the data published by doInBackground() via publishProgress().

A Sample Task

As mentioned earlier, implementing an AsyncTask is not quite as easy as implementing a Runnable. However, once you get past the generics and varargs, it is not too bad.

To see an AsyncTask in action, this section will examine the Threads/AsyncTask sample project.

The Fragment and its AsyncTask

We have a ListFragment, named AsyncDemoFragment:

package com.commonsware.android.async;

import android.app.ListFragment;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemoFragment extends ListFragment {
  private static final String[] items= { "lorem", "ipsum", "dolor",
      "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
      "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
      "vel", "erat", "placerat", "ante", "porttitor", "sodales",
      "pellentesque", "augue", "purus" };
  private ArrayList<String> model=new ArrayList<String>();
  private ArrayAdapter<String> adapter=null;
  private AddStringTask task=null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    task=new AddStringTask();
    task.execute();

    adapter=
        new ArrayAdapter<String>(getActivity(),
                                 android.R.layout.simple_list_item_1,
                                 model);
  }

  @Override
  public void onViewCreated(View v, Bundle savedInstanceState) {
    super.onViewCreated(v, savedInstanceState);

    getListView().setScrollbarFadingEnabled(false);
    setListAdapter(adapter);
  }

  @Override
  public void onDestroy() {
    if (task != null) {
      task.cancel(false);
    }

    super.onDestroy();
  }

  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        if (isCancelled())
          break;
        
        publishProgress(item);
        SystemClock.sleep(400);
      }

      return(null);
    }

    @Override
    protected void onProgressUpdate(String... item) {
      if (!isCancelled()) {
        adapter.add(item[0]);
      }
    }

    @Override
    protected void onPostExecute(Void unused) {
      Toast.makeText(getActivity(), R.string.done, Toast.LENGTH_SHORT)
           .show();

      task=null;
    }
  }
}

(from Threads/AsyncTask/app/src/main/java/com/commonsware/android/async/AsyncDemoFragment.java)

This is another variation on the lorem ipsum list of words, used frequently throughout this book. This time, rather than simply hand the list of words to an ArrayAdapter, we simulate having to work to create these words in the background using AddStringTask, our AsyncTask implementation.

In onCreate(), we call setRetainInstance(true), so Android will retain this fragment across configuration changes, such as a screen rotation. Since our fragment is being newly created, we initialize our model to be an ArrayList of String values, plus kick off our AsyncTask (the AddStringTask inner class, described below), saving the AddStringTask in a task data member. Then, in onViewCreated(), we set up the adapter and attach it to the ListView, also preventing the ListView scrollbars from fading away as is their norm.

In the declaration of AddStringTask, we use the generics to set up the specific types of data we are going to leverage. Specifically:

  1. We do not need any configuration information in this case, so our first type is Void
  2. We want to pass each string “generated” by our background task to onProgressUpdate(), so we can add it to our list, so our second type is String
  3. We do not have any results, strictly speaking (beyond the updates), so our third type is Void

The doInBackground() method is invoked in a background thread. Hence, we can take as long as we like. In a production application, we would be, perhaps, iterating over a list of URLs and downloading each. Here, we iterate over our static list of lorem ipsum words, call publishProgress() for each, and then sleep 400 milliseconds to simulate real work being done. We also call isCancelled() on each pass, to see if our task has been cancelled, skipping the work if it has so we can clean up this background thread.

Since we elected to have no configuration information, we should not need parameters to doInBackground(). However, the contract with AsyncTask says we need to accept a varargs of the first data type, which is why our method parameter is Void....

Since we elected to have no results, we should not need to return anything. Again, though, the contract with AsyncTask says we have to return an object of the third data type. Since that data type is Void, our returned object is null.

The onProgressUpdate() method is called on the UI thread, and we want to do something to let the user know we are progressing on loading up these strings. In this case, we simply add the string to the ArrayAdapter, so it gets appended to the end of the list. However, we only do this if we have not already been canceled.

The onProgressUpdate() method receives a String... varargs because that is the second data type in our class declaration. Since we are only passing one string per call to publishProgress(), we only need to examine the first entry in the varargs array.

The onPostExecute() method is called on the UI thread, and we want to do something to indicate that the background work is complete. In a real system, there may be some ProgressBar to dismiss or some animation to stop. Here, we simply raise a Toast and set task to null. We do not need to worry about calling isCancelled(), because onPostExecute() will not be invoked if our task has been cancelled.

Since we elected to have no results, we should not need any parameters. The contract with AsyncTask says we have to accept a single value of the third data type. Since that data type is Void, our method parameter is Void unused.

To use AddStringTask, we simply create an instance and call execute() on it. That starts the chain of events eventually leading to the background thread doing its work.

If AddStringTask required configuration parameters, we would have not used Void as our first data type, and the constructor would accept zero or more parameters of the defined type. Those values would eventually be passed to doInBackground().

Our fragment also has an onDestroy() method that calls cancel() on the AsyncTask if it is still outstanding (task is not null). This work of cancelling the task and checking to see if the task is cancelled exists for two reasons:

  1. Efficiency, as we should skip any serious work that is not needed if our task itself is not needed
  2. To avoid a crash if we attempt to raise a Toast on a destroyed activity, such as the user launching the activity, then pressing BACK before we complete the background work and display the Toast

The Activity and the Results

AsyncDemo is an Activity with the standard recipe for kicking off an instance of a dynamic fragment:

package com.commonsware.android.async;

import android.app.Activity;
import android.os.Bundle;

public class AsyncDemo extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getFragmentManager().findFragmentById(android.R.id.content) == null) {
      getFragmentManager().beginTransaction()
                          .add(android.R.id.content,
                               new AsyncDemoFragment()).commit();
    }
  }
}

(from Threads/AsyncTask/app/src/main/java/com/commonsware/android/async/AsyncDemo.java)

If you build, install, and run this project, you will see the list being populated in “real time” over a few seconds, followed by a Toast indicating completion.

Threads and Configuration Changes

One problem with the default destroy-and-create cycle that activities go through on a configuration change comes from background threads. If the activity has started some background work — through an AsyncTask, for example – and then the activity is destroyed and re-created, somehow the AsyncTask needs to know about this. Otherwise, the AsyncTask might well send updates and final results to the old activity, with the new activity none the wiser. In fact, the new activity might start up the background work again, wasting resources.

That is why, in the sample above, we are retaining the fragment instance. The fragment instance holds onto its data model (in this case, the ArrayList of Latin words) and knows not to kick off a new AsyncTask just because the configuration changed. Moreover, we retain that data model, so the new ListView created due to the configuration change can work with a new adapter backed by the old data model, so we do not lose our existing set of Latin words.

We also have to be very careful not to try referring to the activity (via getActivity() on the fragment) from our background thread (doInBackground()). Because, suppose that during the middle of the doInBackground() processing, the user rotates the screen. The activity we work with will change on the fly, on the main application thread, independently of the work being done in the background. The activity returned by getActivity() may not be in a useful state for us while this configuration change is going on.

However, it is safe for us to use getActivity() from onPostExecute(), and even from onProgressUpdate(). For those callbacks, either the configuration change has not yet happened, or it has been completed — we will not be in the middle of the change.

Where Not to Use AsyncTask

AsyncTask, particularly in conjunction with a dynamic fragment, is a wonderful solution for most needs for a background thread.

The key word in that sentence is “most”.

AsyncTask manages a thread pool, from which it pulls the threads to be used by task instances. Thread pools assume that they will get their threads back after a reasonable period of time. Hence, AsyncTask is a poor choice when you do not know how long you need the thread (e.g., thread listening on a socket for a chat client, where you need the thread until the user exits the client).

About the AsyncTask Thread Pool

Moreover, the thread pool that AsyncTask manages has varied in size.

In Android 1.5, it was a single thread.

In Android 1.6, it was expanded to support many parallel threads, probably more than you will ever need.

In Android 3.2, it has shrunk back to a single thread, if your android:targetSdkVersion is set to 13 or higher. This was to address concerns about:

If you wish, starting with API Level 11, you can supply your own Executor (from the java.util.concurrent package) that has whatever thread pool you wish, so you can manage this more yourself. In addition to the serialized, one-at-a-time Executor, there is a built-in Executor that implements the old thread pool, that you can use rather than rolling your own.

If your minSdkVersion is 11 or higher, use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) if you specifically want to opt into a multi-thread thread pool. If your minSdkVersion is below 11, you will still want to do that… but only on API Level 11+ devices, falling back to execute() on the older devices. This static utility method handles this for you:


@TargetApi(Build.VERSION_CODES.HONEYCOMB)
static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task,
                                        T... params) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
  }
  else {
    task.execute(params);
  }
}

To use this, call executeAsyncTask(), passing in your AsyncTask instance and the parameters you would ordinarily have passed to execute().

An explanation of what we are doing here, in terms of the @TargetApi annotation and such, will come later in the book.

Also note that the number of threads in the multiple-thread thread pool has also changed over the years. Originally, that pool could climb to as many as 128 threads, which was far too many. As of Android 4.4, the thread pool will only grow to “the number of CPU cores * 2 + 1”, so on a dual-core device, the thread pool will cap at 5 threads. Further tasks will be queued, up to a maximum of 128 queued tasks.

Alternatives to AsyncTask

There are other ways of handling background threads without using AsyncTask:

Of these, the Runnable options are the easiest to use.

These can also be used to allow the main application thread to postpone work, to be done later on the main application thread. For example, you can use postDelayed() to set up a lightweight polling “loop” within an activity, without needing the overhead of an extra thread, such as the one created by Timer and TimerTask. To see how this works, let’s take a peek at the Threads/PostDelayed sample project.

This project contains a single activity, named PostDelayedDemo:

package com.commonsware.android.post;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class PostDelayedDemo extends Activity implements Runnable {
  private static final int PERIOD=5000;
  private View root=null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    root=findViewById(android.R.id.content);
  }

  @Override
  public void onResume() {
    super.onResume();

    run();
  }

  @Override
  public void onPause() {
    root.removeCallbacks(this);

    super.onPause();
  }

  @Override
  public void run() {
    Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT)
         .show();
    root.postDelayed(this, PERIOD);
  }
}

(from Threads/PostDelayed/app/src/main/java/com/commonsware/android/post/PostDelayedDemo.java)

We want to display a Toast every five seconds. To do this, in onCreate(), we get our hands on the container for an activity’s UI, known as android.R.id.content, via findViewById(). Then, in onResume(), we call a run() method on our activity, which displays the Toast and calls postDelayed() to schedule itself (as an implementation of Runnable) to be run again in PERIOD milliseconds. While our activity is in the foreground, the Toast will appear every PERIOD milliseconds as a result. Once something else comes to the foreground — such as by the user pressing BACK — our onPause() method is called, where we call removeCallbacks() to “undo” the postDelayed() call.

And Now, The Caveats

Background threads, while eminently possible using AsyncTask and kin, are not all happiness and warm puppies. Background threads not only add complexity, but they have real-world costs in terms of available memory, CPU, and battery life.

To that end, there is a wide range of scenarios you need to account for with your background thread, including:

  1. The possibility that users will interact with your activity’s UI while the background thread is chugging along. If the work that the background thread is doing is altered or invalidated by the user input, you will need to communicate this to the background thread. Android includes many classes in the java.util.concurrent package that will help you communicate safely with your background thread.
  2. The possibility that the process will be terminated while your work is still going on. This is why in many cases, rather than use an AsyncTask or a bare Thread, you will wind up using a Service, such as an IntentService. This will be explored in greater detail later in this book.
  3. The possibility that your user will get irritated if you chew up a lot of CPU time and battery life without giving any payback. Tactically, this means using ProgressBar or other means of letting the user know that something is happening. Strategically, this means you still need to be efficient at what you do — background threads are no panacea for sluggish or pointless code.
  4. The possibility that you will encounter an error during background processing. For example, if you are gathering information off the Internet, the device might lose connectivity. Alerting the user of the problem via a Notification and shutting down the background thread may be your best option.

Event Buses

Event-driven programming has been around for nearly a quarter-century. Much of Android’s UI model is event-driven, where we find out about these events via callbacks (e.g., onCreate() for the “start an activity” event) and registered listeners (e.g., OnClickListener for when the user taps on a widget).

However, originally, Android did not have a very fine-grained event or message bus implementation that we as developers could use. The Intent system works like a message bus, but it is aimed at inter-process communication (IPC) as much as in-process communication, and that comes with some costs.

However, over time, particularly starting in 2012, event buses started to pop up, and these are very useful for organizing communication within your Android application and across threads. Used properly, an event bus can eliminate the need for AsyncTask and the other solutions for communicating back to the main application thread, while simultaneously helping you logically decouple independent pieces of your code.

What Is an Event Bus?

Whether you consider it an “event bus” (or “message bus”), the “publisher/subscriber” (or “pub/sub”) pattern, or a subset of the “observer” pattern, the programming model where components produce events that others consume is reasonably common in modern software development.

An event bus is designed to decouple the sources of events from the consumers of those events. Or, as one event bus author put it:

I want an easy, centralized way to notify code that’s interested in specific types of events when those events occur without any direct coupling between the code the publishes an event and the code that receives it.

With the traditional Java listener or observer pattern implementation, the component producing an event needs direct access to consumers of that event. Sometimes, that list of consumers is limited to a single consumer, as with many event handlers associated with Android widgets (e.g., just one OnClickListener). But this source-holds-the-sinks coding pattern limits flexibility, as it requires explicit registration by consumers with producers of events, and it may not be that easy for the consumer to reach the producer. Furthermore, such direct connections are considered to be a relatively strong coupling between those components, and often times our objective is to have looser coupling.

An event bus provides a standard communications channel (or “bus”) that event producers and event consumers can hook into. Event producers merely need to hand the event to the bus; the bus will handle directing those events to relevant consumers. This reduces the coupling between the producers and consumers, sometimes even reducing the amount of code needed to source and sink these events.

OK, But Why Are We Bothering With This?

Later on, we are going to have components other than our activities. In particular, we will have services, which are designed to run briefly in the background to perform some operation. Just as communications between activities tends to be loosely coupled, so too are communications between activities and services. An event bus is a great way for the service to let other pieces of the app know that certain work was done (e.g., “the download is complete, so update the UI”).

In the short term, we will use an event bus to have a model fragment let the app know that some data was loaded. In the tutorials, “some data” will be the book contents; in the sample app illustrated in this chapter, “some data” will be some Latin words.

Introducing greenrobot’s EventBus

The event bus implementation that we will be using in the tutorials is greenrobot’s EventBus, an open source implementation based on the Guava project’s event bus. With greenrobot’s EventBus, it is fairly easy to send a message from one part of your app to another disparate part of your app.

To illustrate its use, take a look at the EventBus/AsyncDemo sample project. This is a reworking of a previous example that used an AsyncTask to pretend to download our list of Latin words, populating a ListView with those words as they arrive. This sample replaces the AsyncTask with a model fragment that will keep track of the words and a background thread that will “download” the words. We will use events raised by the model fragment to let the UI fragment know words as they arrive.

Requesting the Artifact

greenrobot’s EventBus is distributed as an artifact that you can integrate in your project via the dependencies in your module’s build.gradle file:

apply plugin: 'com.android.application'

dependencies {
    compile 'de.greenrobot:eventbus:2.2.1'
}

android {
    compileSdkVersion 19
    buildToolsVersion "21.1.2"

  defaultConfig {
    targetSdkVersion 17
  }
}

(from EventBus/AsyncDemo/app/build.gradle)

Here, we are pulling in version 2.2.1. Newer versions, starting with 3.0, have a different artifact and work a bit differently — this is covered later in this chapter.

Defining Events

With greenrobot’s EventBus, the “events” are objects of arbitrary classes that you define. Each different class represents a different type of event, and you can define as many different event classes as you wish. Those classes do not need to inherit from any special base class, or implement some special interface, or have any magic annotations. They are just classes.

You may wish to put data members, constructors, and accessor methods on the event classes, for any data you wish to pass around specific to the event itself. A SearchEvent, for example, might include the search query string as part of the event object.

In our case, we have a WordReadyEvent that contains the new word:

package com.commonsware.android.eventbus;

class WordReadyEvent {
  private String word;
  
  WordReadyEvent(String word) {
    this.word=word;
  }
  
  String getWord() {
    return(word);
  }
}

(from EventBus/AsyncDemo/app/src/main/java/com/commonsware/android/eventbus/WordReadyEvent.java)

Posting Events

To post an event, all you need to do is obtain an instance of an EventBus – typically via the getDefault() method on EventBus — and call post() on it, passing in the event to be delivered to any interested party within your app.

With that in mind, let’s look at the ModelFragment that will be loading in our words:

package com.commonsware.android.eventbus;

import android.app.Fragment;
import android.os.Bundle;
import android.os.SystemClock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import de.greenrobot.event.EventBus;

public class ModelFragment extends Fragment {
  private static final String[] items= { "lorem", "ipsum", "dolor",
      "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
      "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
      "vel", "erat", "placerat", "ante", "porttitor", "sodales",
      "pellentesque", "augue", "purus" };
  private List<String> model=
    Collections.synchronizedList(new ArrayList<String>());
  private boolean isStarted=false;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    if (!isStarted) {
      isStarted=true;
      new LoadWordsThread().start();
    }
  }
  
  public ArrayList<String> getModel() {
    return(new ArrayList<String>(model));
  }

  class LoadWordsThread extends Thread {
    @Override
    public void run() {
      for (String item : items) {
        if (!isInterrupted()) {
          model.add(item);
          EventBus.getDefault().post(new WordReadyEvent(item));
          SystemClock.sleep(400);
        }
      }
    }
  }
}

(from EventBus/AsyncDemo/app/src/main/java/com/commonsware/android/eventbus/ModelFragment.java)

This fragment has no UI — it exists solely to manage a data model on behalf of the rest of the hosting activity. Hence, there is no onCreateView() or any other UI logic directly in this fragment.

In onCreate(), we call setRetainInstance(true), so that if the user rotates the screen or otherwise triggers a configuration change, our model fragment will survive the change and be attached to the new activity instance. Then, if we have not already started the LoadWordsThread, we do so. LoadWordsThread iterates over our list of words, sleeps for 400ms to simulate doing real work, adds each word to an ArrayList of words that it manages… and calls post() to raise a WordReadyEvent to let something else know that the model has changed.

Receiving Events

To receive posted events, you need to do three things:

  1. Call register() on the EventBus to tell it that you have an object that wants to receive events
  2. Call unregister() on the EventBus to tell it to stop delivering events to a previously-registered object
  3. Implement onEventMainThread(), or other onEvent() method flavors, to indicate the type of event you want to receive (and to actually process those events)

This sample app has an AsyncDemoFragment that performs those three steps:

package com.commonsware.android.eventbus;

import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import java.util.ArrayList;
import de.greenrobot.event.EventBus;

public class AsyncDemoFragment extends ListFragment {
  private ArrayAdapter<String> adapter=null;
  private ArrayList<String> model=null;

  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
    adapter=
        new ArrayAdapter<String>(getActivity(),
                                 android.R.layout.simple_list_item_1,
                                 model);

    getListView().setScrollbarFadingEnabled(false);
    setListAdapter(adapter);
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);

    EventBus.getDefault().register(this);
  }

  @Override
  public void onDetach() {
    EventBus.getDefault().unregister(this);

    super.onDetach();
  }

  public void onEventMainThread(WordReadyEvent event) {
    adapter.add(event.getWord());
  }

  public void setModel(ArrayList<String> model) {
    this.model=model;
  }
}
(from EventBus/AsyncDemo/app/src/main/java/com/commonsware/android/eventbus/AsyncDemoFragment.java)

The fragment starts by overriding onViewCreated(), where we create an ArrayAdapter and use that to populate the ListView.

The onAttach() and onDetach() methods are where we indicate to the EventBus that this fragment object wants to receive relevant posted events. onAttach() calls register(); onDetach() calls unregister().

The onEventMainThread() method, via its parameter, indicates that we are interested in WordReadyEvents as they are raised. Our onEventMainThread() method will be called for each WordReadyEvent passed to post() on the EventBus. As the method name suggests, onEventMainThread() is called on the main application thread, so it is safe for us to update our UI. greenrobot’s EventBus is responsible for getting this event to the main application thread — note that we are posting the event from the LoadWordsThread, which is a background thread.

In onEventMainThread(), we get the newly-added word, which we can add to our ArrayAdapter. add() on ArrayAdapter appends the word to the end of the list and informs the attached ListView that the data changed, so the ListView can redraw itself.

What is not obvious, though, from the code in this class is how we are getting the model that we are using in onViewCreated(). AsyncDemoFragment has its own ArrayList of words, set via the setModel() method. Our ArrayAdapter is wrapped around this model. But the master copy of the words is being held by the ModelFragment. If the ModelFragment has the model, and the AsyncDemoFragment needs the model, how are the two being connected?

The Activity

That is handled by our hosting activity, as it sets up these two fragments:

package com.commonsware.android.eventbus;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;

public class AsyncDemo extends Activity {
  private static final String MODEL_TAG="model";
  private ModelFragment mFrag=null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FragmentManager mgr=getFragmentManager();
    FragmentTransaction trans=mgr.beginTransaction();

    mFrag=(ModelFragment)mgr.findFragmentByTag(MODEL_TAG);

    if (mFrag == null) {
      mFrag=new ModelFragment();
      trans.add(mFrag, MODEL_TAG);
    }

    AsyncDemoFragment demo=
        (AsyncDemoFragment)mgr.findFragmentById(android.R.id.content);

    if (demo == null) {
      demo=new AsyncDemoFragment();
      trans.add(android.R.id.content, demo);
    }

    demo.setModel(mFrag.getModel());

    if (!trans.isEmpty()) {
      trans.commit();
    }
  }
}

(from EventBus/AsyncDemo/app/src/main/java/com/commonsware/android/eventbus/AsyncDemo.java)

In onCreate(), we first see if we already have an instance of our model fragment, held by the FragmentManager under a MODEL_TAG tag. If not, we create an instance of the ModelFragment and add it to the FragmentManager, under that tag, via a FragmentTransaction.

We then see if we already have an instance of our AsyncDemoFragment. If not, we create one and add it to the FragmentManager, pouring its UI into android.R.id.content, via another FragmentTransaction.

Then, we connect the two, calling getModel() on the ModelFragment and handing the result to setModel() on the AsyncDemoFragment.

When our activity is newly launched, neither fragment exists. Both fragments are created, and the AsyncDemoFragment gets its model array from the ModelFragment. That array is initially empty. As the ModelFragment adds elements to the array, it posts the WordReadyEvent, which triggers the AsyncDemoFragment to tell the ArrayAdapter and ListView that the model data changed.

If we undergo a configuration change, the ModelFragment is retained, but the AsyncDemoFragment is not. Hence, the activity will always be creating an AsyncDemoFragment. But the model we give to the AsyncDemoFragment may already have words in it, and those words will appear immediately when the ArrayAdapter is wrapped around the model. If the LoadWordsThread is still running, the new AsyncDemoFragment will pick up any new WordReadyEvents that are raised, triggering it to update the ListView as before.

greenrobot’s EventBus 3.x

Some examples in this book use a newer version of greenrobot’s EventBus. Starting with version 3.0, greenrobot’s EventBus has three changes to what we saw in the preceding sections.

First, the artifact has a different package (org.greenrobot) in addition to the higher version number:

apply plugin: 'com.android.application'

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
}

android {
    compileSdkVersion 19
    buildToolsVersion "21.1.2"

  defaultConfig {
    targetSdkVersion 17
    applicationId "com.commonsware.android.eventbus.greenrobot3"
  }
}

(from EventBus/AsyncDemo3/app/build.gradle)

Second, the import statements will pull in classes from the org.greenrobot.eventbus Java package, instead of de.greenrobot.event.

But the biggest change is in how you write the methods that receive events. With EventBus 2.x, you had to use a magic name, like onEventMainThread(). Starting with version 3.0, you now use Java annotations to identify and configure the method, which can have any method name that you want.

In the EventBus/AsyncDemo3 sample project, we have the same code as with the earlier EventBus sample, but updated to use the subscriber approach. Now, the method in AsyncDemoFragment that receives the words is called onWordReady():

  @Subscribe(threadMode = ThreadMode.MAIN)
  public void onWordReady(WordReadyEvent event) {
    adapter.add(event.getWord());
  }

(from EventBus/AsyncDemo3/app/src/main/java/com/commonsware/android/eventbus/AsyncDemoFragment.java)

We indicate to the EventBus system that this method is eligible to receive WordReadyEvent events via the @Subscribe annotation. Java annotations can be configured with key-value pairs; greenrobot’s EventBus uses this for things like the thread mode. So, instead of having to have MainThread at the end of the method name (as with onEventMainThread()), we can now indicate threadMode = ThreadMode.MAIN.

Otherwise, this sample is unchanged from the 2.x edition of the sample.

Overall, this book is slowly migrating to EventBus 3.x, so you will see a mix of 2.x and 3.x for a while.

Visit the Trails!

We will cover much more about jank, and how to detect and diagnose it, in a later chapter.

There are many more features in the greenrobot EventBus implementation. We will see some of those, plus other event bus implementations, in a later chapter on event bus alternatives.