Android Bootable Background Processes

   Posted by: Jim White

By Jim White (Director of Training and Instructor)

Last week, I had the pleasure of spending the week on the east coast teaching Android to a team that is getting ready to develop prototype mobile apps on tablet platforms.  My class was filled with a bunch of talented/smart guys that raised a lot of great questions.  The questions ranged from details on the API to architectural issues.  Over the next few weeks, I thought I would share some of their great questions (and answers I found) through my blog entries.

The first, from Steve, was a question on if it was possible to setup an Android background service to kick off when the hosting device boots up?  The answer is yes, and how to do it is covered below.

Create the Service

First, create your Android service (a class that extends android.app.Service).  For example sake, my demonstration service uses an AsyncTask to establish an Internet connection and check for the availability of a certain web site.  The AsyncTask returns a boolean indicating whether connectivity can be established or not and then the service raises a notification in the status bar to alert the device owner about the site availability.

Here is the code for my example service.

   1: package com.intertech.service;
   2:  
   3: import java.util.concurrent.ExecutionException;
   4: import java.util.concurrent.TimeUnit;
   5: import java.util.concurrent.TimeoutException;
   6:  
   7: import android.app.Notification;
   8: import android.app.NotificationManager;
   9: import android.app.PendingIntent;
  10: import android.app.Service;
  11: import android.content.Context;
  12: import android.content.Intent;
  13: import android.os.IBinder;
  14: import android.util.Log;
  15:  
  16: public class ConnectionCheckerService extends Service {
  17:  
  18:     private ConnectionTask task;
  19:  
  20:     @Override
  21:     public IBinder onBind(Intent arg0) {
  22:         return null;
  23:     }
  24:  
  25:     @Override
  26:     public void onCreate() {
  27:         super.onCreate();
  28:         Log.v("ConnectionChecker", "Connection Checker created");
  29:     }
  30:  
  31:     @Override
  32:     public int onStartCommand(Intent intent, int flags, int startId) {
  33:         Log.v("ConnectionChecker", "Connection Checker started");
  34:         task = new ConnectionTask();
  35:         task.execute();
  36:         notifyConnectionStatus();
  37:         return super.onStartCommand(intent, flags, startId);
  38:     }
  39:  
  40:     @Override
  41:     public void onDestroy() {
  42:         task.cancel(true);
  43:         Log.v("ConnectionChecker", "Stopping ConnectionChecker");
  44:         super.onDestroy();
  45:     }
  46:  
  47:     private void notifyConnectionStatus() {
  48:         Log.v("ConnectionChecker", "Getting task results.");
  49:         while (true) {
  50:             try {
  51:                 Boolean result = task.get(1000, TimeUnit.MILLISECONDS);
  52:                 Context context = getApplicationContext();
  53:                 PendingIntent contentIntent = PendingIntent.getService(context,
  54:                         0, null, 0);
  55:                 Notification notification = new Notification(R.drawable.icon,
  56:                         "Connection Status", System.currentTimeMillis());
  57:                 if (result) {
  58:                     notification.setLatestEventInfo(context,
  59:                             "Connection Service",
  60:                             "Intertech connection available!", contentIntent);
  61:                 } else {
  62:                     notification
  63:                             .setLatestEventInfo(context, "Connection Service",
  64:                                     "Intertech connection not available",
  65:                                     contentIntent);
  66:                 }
  67:                 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  68:                 notificationManager.notify(1, notification);
  69:                 Log.v("ConnectionChecker", "Task results displayed.");
  70:                 break;
  71:             } catch (TimeoutException e) {
  72:                 Log.v("ConnectionChecker", "Task work not completed.");
  73:             } catch (InterruptedException e) {
  74:                 Log.v("ConnectionChecker", "Task work interrupted.");
  75:                 break;
  76:             } catch (ExecutionException e) {
  77:                 Log.v("ConnectionChecker", "Task work failed.");
  78:                 break;
  79:             }
  80:         }
  81:         task.cancel(true);
  82:     }
  83: }

And here is the code for the associated AsyncTask.  I use a separate thread (through the AsyncTask) in this example just to remind you that you probably want to use threads to conduct most work in Android.  While this example is simple, your startup task(s) may be more complex and therefore really require the threading.

   1: package com.intertech.service;
   2:  
   3: import java.io.IOException;
   4:  
   5: import org.apache.http.HttpResponse;
   6: import org.apache.http.client.ClientProtocolException;
   7: import org.apache.http.client.methods.HttpGet;
   8: import org.apache.http.impl.client.DefaultHttpClient;
   9: import org.apache.http.params.BasicHttpParams;
  10: import org.apache.http.params.HttpConnectionParams;
  11: import org.apache.http.params.HttpParams;
  12:  
  13: import android.os.AsyncTask;
  14: import android.util.Log;
  15:  
  16: public class ConnectionTask extends AsyncTask<Void, Void, Boolean> {
  17:  
  18:     private final String LIST_URL = "http://www.intertech.com";
  19:  
  20:     @Override
  21:     protected Boolean doInBackground(Void... arg0) {
  22:         Log.v("ConnectionTask", "Checkinig...");
  23:         HttpParams params = new BasicHttpParams();
  24:         HttpConnectionParams.setConnectionTimeout(params, 4000);
  25:         HttpConnectionParams.setSoTimeout(params, 7000);
  26:         DefaultHttpClient client = new DefaultHttpClient(params);
  27:         HttpGet get = new HttpGet(LIST_URL);
  28:         HttpResponse res;
  29:         try {
  30:             res = client.execute(get);
  31:         } catch (ClientProtocolException e) {
  32:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  33:             return false;
  34:         } catch (IOException e) {
  35:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  36:             return false;
  37:         }
  38:         int code = res.getStatusLine().getStatusCode();
  39:         if (code != 200) {
  40:             Log.v("ConnectionTask", "Unsuccessfully hit Intertech site");
  41:             return false;
  42:         }
  43:         Log.v("ConnectionTask", "Successfully hit Intertech site");
  44:         return true;
  45:     }
  46:  
  47: }

Create a Broadcast Receiver

Android services need something to kick them off.  Typically, services are created and started by activities or even other services.  In this case, since the device is booting, no other application component exists to start your service.  Create a Broadcast Receiver to start on boot of the device and then kickoff the service once started.

Broadcast receivers receive and react to announcements (intents).  Think simple ?listener? or ?event handler.?  They are great for doing small pieces of work in response to an external stimulus.  Announcements like the battery is low, download is complete, etc. can be picked up and reacted to by a Broadcast receiver.  Broadcast receivers are alive for just a short period ? to process the intent.  In this case, one will be used to react to the completion of the boot process.

Here is the code for the service-starting broadcast receiver.

   1: package com.intertech.service;
   2:  
   3: import android.content.BroadcastReceiver;
   4: import android.content.Context;
   5: import android.content.Intent;
   6: import android.util.Log;
   7:  
   8: public class ConnectionCheckerStarter extends BroadcastReceiver {
   9:  
  10:     @Override
  11:     public void onReceive(Context context, Intent intent) {
  12:  
  13:         if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
  14:             Intent serviceIntent = new Intent(context, ConnectionCheckerService.class);
  15:             context.startService(serviceIntent);
  16:         } else {
  17:             Log.e("ConnectionChecker", "Received unexpected intent " + intent.toString());
  18:         }
  19:     }
  20:  
  21: }

Register the Broadcast Receiver in the Manifest

With the service and the broadcast receiver now built, the last step is to register both components in the AndroidManifest.xml file.  Registering the service is easy as it takes no special configuration (with the exception of INTERNET user permissions for the AsyncTask for this example).  Registering the broadcast receiver, however, requires the receiver have an intent-filter for android.intent.action.BOOT_COMPLETED.  This intent is broadcast by Android after the system has finished booting.  Furthermore, user permission must be granted to receive the intent.  Here is the manifest XML code to register both the service and receiver as well as their required user permissions.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   3:     package="com.intertech.service" android:versionCode="1"
   4:     android:versionName="1.0">
   5:     <application android:icon="@drawable/icon" android:label="@string/app_name">
   6:         <service android:name=".ConnectionCheckerService" android:label="ConnectionCheckerService" />
   7:         <receiver android:label="ConnectionCheckerStarter" android:name=".ConnectionCheckerStarter">
   8:             <intent-filter>
   9:                 <action android:name="android.intent.action.BOOT_COMPLETED" />
  10:             </intent-filter>
  11:         </receiver>
  12:     </application>
  13:     <uses-permission android:name="android.permission.INTERNET" />
  14:     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  15: </manifest> 

Results

With this application installed on a device, the service now starts after the device boots - thanks to the receiver.  In this example, the user doesn't see any visual display, save the status bar notification as shown below.

image image

A check of the LogCat indicates the service was successfully started during the boot process.

image

Wrap up

If you are looking to learn Android, please consider signing up for Intertech's Complete Android class (see here for details).  Our next public offering of the class will be held July 26-29.  Sign up today by contacting Dan McCabe at dmccabe@intertech.com


Comments (1)

marcello 1/6/2012 6:53 PM

i am sorry but don't works with ICS (android 4.0 + )    :-(

Add a Comment

*

*

Loading

Find Us
Contact Us 651-288-7000 1-800-866-9884
Home | Training | Curriculum | Course Finder | Schedule | Enroll | Twin Cities Java User Group | Consulting | Foundation | Jobs | About Us | Our Story | Press Room | Instructors | President | Map & Directions | Sitemap

Java Training | JSF / Struts / Spring / Hibernate Training | Java Power Tools Training | .NET 4.0 & Visual Studio 2010 Training | Microsoft Web Development Training | Prism / MVVM / MEF Training | .NET 3.5 and Visual Studio 2008 Training | .NET 2.0 and Visual Studio 2003 Training | Cloud Computing Training | Ajax / Web Services / XML Training | Groovy and Grails Training | SQL Server 2012 Training | SQL Server 2008 Training | SQL Server 2005 Training | Mobile Development Training | SharePoint 2010 Training | SharePoint 2007 Training | Agile, Process, Analysis & Design Training | Arch/Design Patterns Training | Microsoft Official Curriculum Training | Web Development Training | Ruby Training | Rational Application Developer (RAD) Training | WebSphere Application Server Training | WebSphere Portal Training | WebLogic Training | Boot Camp Training | Project Management Training | C / C++ Training | Metro / WinRT / Windows 8 Development Training | Retired

Intertech delivers training on-site and virtually serving cities including Phoenix, AZ | San Francisco, CA | Los Angeles, CA | San Diego, CA | San Jose, CA | Washington, DC | Chicago, IL | Orlando, FL | Boston, MA | Duluth, MN | Minneapolis St. Paul, MN | Rochester, MN | Raleigh-Durham, NC | New York, NY | Philadelphia, PA | Austin, TX | Dallas, TX | Houston, TX | Seattle, WA.