Posted by: David Cheney | November 16, 2010

Multitasking in Android

Asleep at the Wheel

While exploring Android Text-To-Speech I added the required OnInitListener() to be notified when I may speak(“Hello World!”). But I want to speak in a variety of methods in my code, not in OnInitListener. How do I wait upon OnInitListener in my main line?

As a trial I added:
while (! mIsTtsReady || i>limit) try { Thread.sleep(100); i++; };

and in OnInitListener:
@Override public void OnInit() { mIsTtsReady = true; }

Though I knew that sleep polling was not the proper way to handle this, I did expect it to work. But OnInit never runs. Why??

The failure prompted this post on Stack Overflow. My theory was that OnInit has to run on my thread – which of course is in a tight sleep() loop. And the TTS code confirms: OnServiceConnected() runs in my thread (lines 396-404).

Enough of that. Time to bite the bullet and learn the correct way to do such things. If you’re laughing at this point then this article is not for you – unless you enjoy such entertainment or care to add your insights to what follows :)

Awaiting your command

You have an Activity. What happens in your code after OnStart()? A typical answer could well be “when the user does X, Y happens. Or, if they do Q ….” Clearly we’re not blocked on X – or on any single one of the many events that could occur.

An “upon some event my thread runs here” model is used throughout Android:

Android applications don’t have a single entry point for everything in the application… rather, they have essential components that the system can instantiate and run as needed: Activities, Services, Content Providers … are instantiated in the main thread. [Fundamentals]

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. [Handler]

One single thread magically appears and runs as needed (so long as it’s not asleep ;p). Further, most of us are at least aware of programming a separate thread to run time consuming background processes while keeping alert for UI events. It seems that sooner or later we’ll want to synchronize threads – and even operations within a thread. What we need is a way to wait for multiple possible things. How is that done?

I thought Android’s Handler might provide an answer but was still unclear on how it worked and when to use it. Documentation is spare and there is tenuous linkage between detail and attempts at some sort of integrated view. My three Android books have a total of that many pages on Handler. The posts at MindTheRobot and Satya Komatineni are much better than the official doc, which is sparse even where more explanation is provided. Between curiosity and the sense that all this was worth clarity, I decided to read the code itself. Here is what I found.

Messages and Handling

Implicit in every Android Application is a general facility for waiting until there is something in an “inbox” and then “dispatching” the processor to the right code to do it. In this context:

  • the “something to do” (including responding to hardware events) is represented by a Message instance
  • the “inbox” is an instance of a MessageQueue
  • “the right code to do it” is put in an instance of Handler
  • the “general facility for waiting and dispatching” is the Looper class

If you’re in a hurry, it might help to know that you can focus on the Message and Handler. The rest you can almost take for granted: Looper is built into a Context and provides the “magic” of waiting and dispatching to the right Handler – only when you create a separate Thread might you want it to call the static Looper.prepare() (or just use new HandlerThread()). A MessageQueue is associated with each Looper as an inbox to hold Messages while the app is busy or to awaken its Looper for dispatch. If you like details, see my posts for Android’s Looper and Android’s MessageQueue.

What you’re likely to use directly are Messages and Handlers. For example, to recognize TTS initialization I needed to put my code in a Handler and to replace my mIsTtsReady with a Message. After onStart() my activity would go to sleep – and yet awaken to run OnInitListener() just as it might to handle a user selection. If I wanted my speech code in a different thread – or anywhere other than in the direct path out of OnInitListener – I needed to use the same model within my code.

Messages primarily contain some members for you to populate with the semantic information that you want to pass along: the “what”, etc. You build the semantics themselves by overriding (or implementing) a handler’s handleMessage(). If you’re into message structure, see Android’s Message.

Using Handler

The top things to understand about a Handler are:

- a Handler is not only a message receiver, by default that same handler is that same message’s constructor and sender. That’s right, you read correctly. To send a message get a reference to the target Handler. Obtain a blank message, complete it, and send it via that same Handler reference. The handler “will deliver messages to the message queue and execute them as they come out of the message queue.” [ref] My conjecture is this: by addressing a message to itself we guarantee that the sender and the receiver are the very same class, tightly coupling responsibilities of message constructor and message interpreter. No ‘spam’ from unknown senders, and no excuses from service provider “handlers” claiming not to have understood your message.

- at the right time, on the right thread, the code you put in the handler will run. There we have the whole purpose of the Handler: to run code at a different time and/or on a different thread: “There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.” [ref]

- a Handler can send (and be sent) objects, including Runnables. That is, so long as you are within the same application you can send a reference to an object, or to code to be executed later and/or elsewhere. Though these are handled identically during send their processing upon reception is different enough to warrant a different verb: we send() data; we post() a Runnable.

- messages not containing a reference to an object or runnable are Parcelable, that is, they can be written to and restored from a Parcel for remote delivery via AIDL.

- messages are sent to handlers so often that it makes sense to keep a pool of messages available for use and recycling. See the Handler’s obtainMessage() methods.

For internals, refer to my post Android’s Handler.

Putting it into Practice

To test Messages and Handlers I wrote Worker, which creates a HandlerThread and associates Handlers A and B:

public class Worker {

  private static final String TAG = "worker";
  private HandlerThread mHandlerThread = null;
  Handler mHandlerA = null;
  Handler mHandlerB = null;

  public Worker() {
  mHandlerThread = new HandlerThread(TAG);
  mHandlerThread.start();

  mHandlerA = new Handler(mHandlerThread.getLooper()) {
   @Override
   public void handleMessage(Message message) {
   Log.d(TAG, "A: " + message.toString());
   handlerB.sendEmptyMessageDelayed(-2,100);
   }
  };

  mHandlerB = new Handler(mHandlerThread.getLooper()) {
   @Override
   public void handleMessage(Message message) {
   Log.d(TAG, "B: " + message.toString());
   getHandlerL().sendEmptyMessage(-9876); // To: handlerL on boss thread
   }
  };
  }
}

And to exercise the class, code such as:

public class BossActivity extends Activity {

  private static final String TAG = "boss";
  Worker mWorker = null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   mWorker = new Worker(); // runs a thread "worker"
  }

  @Override
  protected void onStart() {
   super.onStart();
   mWorker.handlerA.sendEmptyMessage(1234); // To: handlerA on worker
  }

  @Override
  protected void onPause() {
   mWorker.handlerB.sendEmptyMessage(6789); // To: handlerB on worker
  }

  private static Handler handlerL = new Handler() {
  @Override
  public void handleMessage(Message message) {
   Log.d(TAG, "L: " + message.toString());
  }
  };

  static Handler getHandlerL() {
   return handlerL;
  }
}

Results, of course, appear only in Logcat.

--

Though I feel I have a grasp of what this Message/Handler/etc infrastructure is, I've only begun to learn about when to use it. I invite your comments.

best,
Dave

About these ads

Responses

  1. Thank you! Your code was laid out well in such a way that I learnt alot from a little bit of code!

    Some minor fixes:
    (i) mHandlerA|B and handlerA|B are the same member variable
    (ii) add super call in onPause()
    @Override
    protected void onPause() {
    super.onPause();
    mWorker.handlerB.sendEmptyMessage(6789); // To: handlerB on worker
    }

  2. Hey Dave,

    Very cool to see your recent work. Considering the great job you did on Ocean Futures Ambassadors video I have no doubt you are doing great things. Cheers,
    Jim


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

Follow

Get every new post delivered to your Inbox.