Android Service creation and consumption

Posted August 7th, 2008 by Nazmul

Comprehensive Real-World BlackBerry Training Courses by developerlife.com

Want to learn from the Masters? We’ve created groundbreaking BlackBerry software (we are finalists in the 2009 BlackBerry Developer Challenge). We have a complete set of instructor-led training courses available for BlackBerry development that will turbo-charge your BlackBerry development efforts. Whether you are a newbie or an experienced developer, we have modules that will fit your needs. Learn more about our courses & schedule.

This tutorial will show you how to create a simple service, that does not use IPC (inter process communication). Services are great for running long running tasks and business logic, outside an Activity, which is tied to the user interface. For example, if you have a background task that has to download data periodically, then you should put that task in a Service. You can explicitly start a service and stop it as well. With IPC you can connect to a running service and call methods on it, however, in this example, I won’t be using any IPC; instead all data transfer will happen via a shared object and a listener.

Android 101

To get started with Android, click here. Instead of reading the SDK docs to get the basics, I recommend that you read this book to get going.

Service creation

There are really 2 steps to creating a service, this is in addition to whatever code you want the service to execute:

  • Create the class – for this you have to extend the Service class. You have to override the onCreate() and onDestroy() methods, which get executed when your service is started and stopped. There are other lifecycle methods that you can override, which are of interest if you’re using IPC, but we are keeping things simple in this tutorial.
  • Update android manifest (AndroidManifest.xml) – You have to list the class name of your Service in this XML file.

The following is an example of a service called MyService that periodically gets some data from a web service, and saves it to a shared object (static object). Here’s the AndroidManifest.xml entry for this service:

    <service android:name=".myservice.MyService"/>

Here’s the Java code for the MyService implementation itself:

package com.developerlife.myservice;

/**
 * MyService
 *
 * @author Nazmul Idris
 * @version 1.0
 * @since Jul 21, 2008, 12:03:01 PM
 */
public class MyService extends Service {

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// constants
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public static final String ServletUri = "http://" + AppUtils.EmulatorLocalhost + ":8080/Ping";

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// static data/shared references, etc.
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public static ServiceUpdateUIListener UI_UPDATE_LISTENER;
private static MainActivity MAIN_ACTIVITY;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// data
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
private static Hashtable<String, Hashtable<DataKeys, String>> weatherData =
    new Hashtable<String, Hashtable<DataKeys, String>>();
private Timer timer = new Timer();
private static final long UPDATE_INTERVAL = 5000;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// hooks into other activities
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public static void setMainActivity(MainActivity activity) {
  MAIN_ACTIVITY = activity;
}

public static void setUpdateListener(ServiceUpdateUIListener l) {
  UI_UPDATE_LISTENER = l;
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// lifecycle methods
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

/** not using ipc... dont care about this method */
public IBinder onBind(Intent intent) {
  return null;
}

@Override protected void onCreate() {
  super.onCreate();

  // init the service here
  _startService();

  if (MAIN_ACTIVITY != null) AppUtils.showToastShort(MAIN_ACTIVITY, "MyService started");
}

@Override protected void onDestroy() {
  super.onDestroy();

  _shutdownService();

  if (MAIN_ACTIVITY != null) AppUtils.showToastShort(MAIN_ACTIVITY, "MyService stopped");
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// service business logic
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
private void _startService() {
  timer.scheduleAtFixedRate(
      new TimerTask() {
        public void run() {
          _getWeatherUpdate();
        }
      },
      0,
      UPDATE_INTERVAL);
  Log.i(getClass().getSimpleName(), "Timer started!!!");
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// weather data that the service gets...
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
public static Hashtable<String, Hashtable<String, String>> DataFromServlet =
    new Hashtable<String, Hashtable<String, String>>();

/** dont forget to fire update to the ui listener */
private void _getWeatherUpdate() {
  // http post to the service
  Log.i(getClass().getSimpleName(), "background task - start");

  Hashtable<String, String> map = new Hashtable<String, String>();
  map.put("key", "value");

  try {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(map);

    PostMethod post = HttpUtils.sendMonitoredPOSTRequest(ServletUri,
                                                         null,
                                                         new ByteBuffer(baos.toByteArray()),
                                                         null);
    ByteBuffer data = HttpUtils.getMonitoredResponse(null, post);

    ObjectInputStream ois = new ObjectInputStream(data.getInputStream());
    DataFromServlet =
        (Hashtable<String, Hashtable<String, String>>) ois.readObject();

    Log.i(getClass().getSimpleName(), "data size from servlet=" + data.toString());
    Log.i(getClass().getSimpleName(), "data hashtable from servlet=" + DataFromServlet.toString());

  }
  catch (Exception e) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    e.printStackTrace(pw);
    Log.e(getClass().getSimpleName(), sw.getBuffer().toString(), e);
  }

  Log.i(getClass().getSimpleName(), "background task - end");

  if (UI_UPDATE_LISTENER != null) {
    UI_UPDATE_LISTENER.updateUI(DataFromServlet);
  }
}

private void _shutdownService() {
  if (timer != null) timer.cancel();
  Log.i(getClass().getSimpleName(), "Timer stopped!!!");
}

}//end class MyService

Notes on the code:

  1. the onBind() method returns null; I’m not using IPC, which is why null is being returned. If you do use IPC then you have to return the stub here.
  2. onCreate() creates the background thread that periodically checks some web service for updates. The web service URI is contained in ServletUri class variable. The background thread is started using a recurring Timer.
  3. onDestroy() shuts down the background thread that periodically checks some web service for updates. This method stops the background timer started in onCreate().
  4. The bulk of the work is performed in _getWeatherUpdate()… this method performs the business logic of the recurring background task. When updates are receieved, notifications are fired to the UI_UPDATE_LISTENER. Also, all data from the network is stored in a static object DataFromServlet – which is used by other components to get this data once the UI_UPDATE_LISTENER is called.

Here’s the listener interface that’s invoked when the service gets updates from the network:

public interface ServiceUpdateUIListener {

public void updateUI(Hashtable<String, Hashtable<String, String>> data);

}//end interface ServiceUpdateUIListener

The listener is pretty straighforward. If you want to implement this listener interface in GUI code, so that updates that you get are then drawn to the screen/Activity, then you have to wrap the code in UIThreadUtilities.runInUIThread(), here’s an example:

  MyService.setUpdateListener(new ServiceUpdateUIListener() {
    public void updateUI(final Hashtable<String, Hashtable<String, String>> newData) {
      // make sure this runs in the UI thread... since it's messing with views...
      UIThreadUtilities.runOnUIThread(
          context,
          new Runnable() {
            public void run() {
              if (newData.size() == _data.size()) {
                if (newData.keySet().equals(_data.keySet())) return;
              }

              AppUtils.showToastShort(context,
                                      "Data updated");

              // update the saved weather data
              _data.clear();
              _data.putAll(newData);

              // tell the view to refresh since the model changed.
              WeatherDataListAdapter.this.notifyDataSetChanged();
            }
          });
    }
  });

Notes on this code:

  1. A Runnable implementation is created and passed to runOnUIThread to make sure that the code in it’s run() method is executed in the UI thread. This is important to do, since you don’t want anything outside the UI thread making drawing updates on the UI components.
  2. The data in the newData Hashtable that’s passed to this method is downloaded and created in MyService’s background Timer thread… that’s the extent to what can be done in a background thread…. at this point the data must be visually rendered, which is why it’s done on the UI Thread.

Service consumption

The code so far has shown you how to create a service, and hook it up to UI elements in your project. However, you have to start the service and stop it in your main Activity, so that all sub Activities will have access to the service. To start/stop the service, before you use it, you must:

  • To start : create an intent to start the service (not using IPC bind/unbind) in activity that uses the service
  • To stop : create an intent to stop the service, in activity that uses the service.

Here’s code examples to do this:

public class MainActivity extends SimpleActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
  super.onCreate(icicle);
  try {

    // setup and start MyService
    {
      WeatherService.setMainActivity(this);
      Intent svc = new Intent(this, MyService.class);
      startService(svc, Bundle.EMPTY);
    }

  }
  catch (Exception e) {
    Log.e(Global.TAG, "ui creation problem", e);
  }

}

@Override protected void onDestroy() {
  super.onDestroy();

  // stop MyService
  {
    Intent svc = new Intent(this, MyService.class);
    stopService(svc);
  }

}

Comments and Feedback

To share your thoughts and feedback on this tutorial, click here.

Training Services

Want to learn from the best in the business? We have training programs available for BlackBerry development, Android development, rich desktop apps, and UX design. We can give your development team a competitive edge, and make them experts in these technologies. Contact us if you are interesting in learning more about our training services & schedule.

Consulting Services

If you need help building web, mobile, and desktop apps that are all connected to the cloud, we can help. We can empower your business by bringing your ideas to life. Contact us if you have a project you need our help with and we will consider taking you on as a client.

Our expertise: architecture, UX design, graphic design, and implementation services for BlackBerry, Android, GWT, desktop Java, and cloud computing. Our specialties: crafting stunning UXes, LBS, real-time collaboration and syncing between services and web/mobile/desktop apps, location based mobile e-commerce, and location based mobile advertising.


Comments are closed.