Multitasking with Handler and Message

The Handler is the Swiss army knife of messaging and scheduling operations for Android. This class allows you to queue tasks to be run on different threads and allows you schedule tasks using Message and Runnable objects.

The Android platform monitors the responsiveness of applications and kills those that are considered nonresponsive. An Application Not Responding (ANR) event is defined as no response to a user input for five seconds. (A user touches the screen, or presses a key, or the like, and your application must respond). So does this mean your code always has to complete within five seconds? No, of course not, but the main UI thread does have to respond within that time frame. To keep the main UI thread snappy, any long-running tasks, such as retrieving data over the network or getting a large amount of data from a database or complicated calculations, should be performed in a separate thread.

Getting tasks into a separate thread, then getting results back to the main UI thread is where the Handler, and related classes, come into play. When a Handler is created, it is associated with a Looper. A Looper is a class that contains a MessageQueue and processes Message or Runnable objects that are sent via the Handler.

In the Handler usage, shown in listings 3.3 and 3.4, we created a Handler with a no-argument constructor. With this approach, the Handler is automatically associated with the Looper of the current running thread, typically the main UI thread. The main UI thread, which is created by the process of the running application, is an instance of a HandlerThread, which is basically an Android Thread specialization that provides a Looper. The key parts involved in this arrangement are depicted in the diagram in figure 3.5.

MainUIThread

(HandlerThread)

Handler myHandler = new Handler() {

public void handleMessage (Message m) { updateUIHere();

Message m = myHandler.obtainMessage(); Bundle b = new Bundle(); b.putString("key", "value"); m.setData(b);

myHandler.sendMessage(m);

Figure 3.5 Usage of the Handler class with separate threads, and the relationship of HandlerThread, Looper, and MessageQueue

Figure 3.5 Usage of the Handler class with separate threads, and the relationship of HandlerThread, Looper, and MessageQueue

When implementing a Handler you will have to provide a handleMessage(Message m) method. This method is the hook that lets you pass messages. When you create a new Thread, you can then call one of several sendMessage methods on Handler from within that thread's run method, as our examples and diagram demonstrate. Calling sendMessage puts your message on the MessageQueue, which the Looper maintains.

Along with sending messages into handlers, you can also send Runnable objects directly, and you can schedule things to be run at different times in the future. You send messages and post runnables. Each of these concepts supports methods such as sendEmptyMessage(int what), which we have already used, and the counterparts sendEmptyMessageAtTime(int what, long time) and sendEmptyMessageDelayed(int what, long delay). Once it is in the queue, your message is processed as soon as possible (unless you schedule or delay it using the respective send or post method).

You will see more of Handler and Message in other examples throughout the book, and we will cover more detail in some instances, but the main point to remember when you see these classes is that they are used to communicate between threads and for scheduling.

Getting back to our RestaurantFinder application and more directly view-oriented topics, we next need to elaborate on the ReviewAdapter our RestaurantFinder ReviewList screen now uses, after it is populated with data from a Message. This adapter returns a custom View object for each data element it processes.

0 0

Post a comment