Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art
HomeF.A.Q.
Community
Writing Recipes
Login
Sending messages between threads using activity thread queue and Handler class
Contributed by Vladimir Kroz 2010-11-19 02:53:43 (updated 2011-12-16 03:33:32)
In Published Edition? Yes
Minimum Version 1.5
0
Votes
Problem

As an example, you might require to use AndroidPlot, a library to plot charts and graphs in your application or use OpenStreetMaps. For this your application needs to reference these libraries.

ADT Plugin Version 17 or later:

  • Ensure that your project has a folder with the exact name of "libs" (not the traditional "lib").
  • Download the library JAR file into this folder.

You are done: Eclipse (and the standard Ant build process) will now add your Jar file to the project's classpath.

ADT Plugin Version 16 or earlier (legacy)

In Eclipse you need to specify the Jar file in your build path:

  • Create your project as described in earlier recipes;
  • Download the JAR file corresponding to the library you wish to use.

For future reference you should create a folder called "libs" (not lib) and store the Jar file there.

  • Open your Android project in Eclipse, right click on the project name and select 'Properties' option in the menu.

  • From the list on the left side, select 'Java Build Path' and click on the 'Libraries' tab.
Solution
  • Write a nested class that extends Android's Handler class; override the handleMessage() method which will read messages from thread queue;
  • Pass this Handler to the worker thread, usually via the worker class' constructor;
  • In the worker thread, post messages using the various obtainMessage() and sendMessage() methods;
  • This will cause the Activity to be called at the handleMessage() method, but on the event thread so you can safely update the GUI.
Discussion

There are many situations when it is required to have a thread running in the background and send information to main Activity's UI thread. At the architectural level there are different approaches that can be taken:

  1. Use of Android AsyncTask class
  2. Start a new thread

Though using AsyncTask is very convenient, there are a situations when you really need to construct a worker thread by yourself. In such situation you likely will need to send some information back to Activity thread. Keep in mind that Android doesn't allow other threads to modify any content of main UI thread. Instead you're required to wrap data into Messages and send them through message queue. The implementation consists of two parts.

1) Add handler

Add an instance of Handler class to e.g., your MapActivity instance.

public class MyMap extends MapActivity {
    . . . 
    public Handler _handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Log.d(TAG, String.format("Handler.handleMessage(): msg=%s", msg));
            // This is where main activity thread receives messages
            // Put here your handling of incoming messages posted by other threads
			super.handleMessage(msg);
		}

	};
. . . .

}

2) Post Message

In the worker thread post a message to activity main queue whenever you need Add handler class instance to your MapActivity instance.

	/**
	 * Performs background job
	 */
	 class MyThreadRunner implements Runnable {
		// @Override
		public void run() {
			while (!Thread.currentThread().isInterrupted()) {
// Just dummy message -- real implementation will put some meaningful data in it
				Message msg = Message.obtain();
				msg.what = 999;
				MyMap.this._handler.sendMessage(msg);
// Dummy code to simulate delay while working with remote server
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
				}
			}
		}
	 }
Comments (1)
Leave a comment
Edit History (6)
JimT-Utah said 2013-08-21 12:34:05 I can't make this recipe work I have an array of images that I want to display in sequence to represent the operation of a piece of hardware. When I loop through them in my MainActivity, everything goes as expected. What I really want to do, though, is run the sequence in a thread while I’m doing more important stuff in the main thread. I put the array and two classes inside my MainActivity class. When I compile my program, I get a “No enclosing instance of the type MainActivity.postPix is accessible in scope” error. What do I need to do to get it to work? int coil_array[] = { R.drawable.coil0, R.drawable.coil1, R.drawable.coil2, R.drawable.coil3, R.drawable.coil4, R.drawable.coil5, R.drawable.coil6, R.drawable.coil7 }; public class postPix extends MainActivity { public Handler _handler = new Handler() { @Override public void handleMessage(Message msg) { coil_image.setBackgroundResource(msg.what); super.handleMessage(msg); }; }; } public class display_loop implements Runnable { public void run() { int coil_index = 0; control_variable = true; while (control_variable) { if (MainActivity.current_state != state.Charging) control_variable = false; try { coil_index = (++coil_index) % 8; Message msg = Message.obtain(); msg.what = coil_index; ******** postPix.this._handler.sendMessage(msg); Thread.sleep(100); } catch (Exception ex) { String S = ex.getLocalizedMessage(); S = "Error" + S; } } return; } }