- What is an Android Service? / What Is an <tt>IntentService</tt>?
- When Should You Consider Using <tt>IntentService</tt>?
- A Simple <tt>IntentService</tt> Example
A Simple IntentService Example
Let’s look at a simple example of an IntentService. Say we have an app that needs to do some task each time a Button control on a specific screen is clicked, but that the task itself takes a bit of time to complete, for some reason or another. Regardless of the reason, you find that every time the user clicks this Button, the entire application becomes unresponsive. The user must wait for the task to finish before he can continue using the application because the task is being completed on the main thread.
Here’s a bit of sample code that you could drop into a Button control click handler and cause a 5-second delay in your application (our pretend “task”):
EditText input = (EditText) findViewById(R.id.txt_input); String strInputMsg = input.getText().toString(); SystemClock.sleep(5000); TextView result = (TextView) findViewById(R.id.txt_result); result.setText(strInputMsg + " " + DateFormat.format("MM/dd/yy h:mmaa", System.currentTimeMillis()));
All this click handler does is retrieve some text from an EditText control on the screen, hang around doing nothing for 5 seconds, and then generate some information to display in the EditText control as a result. In reality, your application would probably not just be sitting around sleeping, but doing some real work. But regardless, we would much rather keep these task requests (Button clicks) from interfering with the application, so we decide to implement a simple IntentService to handle.
Here’s our simple IntentService implementation:
public class SimpleIntentService extends IntentService { public static final String PARAM_IN_MSG = "imsg"; public static final String PARAM_OUT_MSG = "omsg"; public SimpleIntentService() { super("SimpleIntentService"); } @Override protected void onHandleIntent(Intent intent) { String msg = intent.getStringExtra(PARAM_IN_MSG); SystemClock.sleep(5000); String resultTxt = msg + " " + DateFormat.format("MM/dd/yy h:mmaa", System.currentTimeMillis()); Intent broadcastIntent = new Intent(); broadcastIntent.setAction(ResponseReceiver.ACTION_RESP); broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); broadcastIntent.putExtra(PARAM_OUT_MSG, resultTxt); sendBroadcast(broadcastIntent); } }
Intent extras are used to send some data associated with the specific task request, in a manner similar to passing data between Activity classes. In this case, we just take the incoming EditText contents and package them into the PARAM_IN_MSG extra, but you could bundle up and send anything needed to complete the specific instance of the task request as part of the Intent extras.
Once the processing is complete, we use a broadcast intent to tell anyone interested that the service has finished the task. Your IntentService need only do this if the user interface needs to be updated. If the task simply updated the underlying application database, or the shared preferences, or what have you, then your application would not need to be informed directly, as Cursor objects and such would be updated automatically when some underlying data changed. Don’t forget to register your SimpleIntentService in your Android Manifest file, like this:
<service android:name="SimpleIntentService"/>
Next, turn your attention back to the application Activity that hosts your application user interface with the Button control. Update the Button click handler to send a new task request to the SimpleIntentService. The request is packaged up as an Intent, the incoming parameter is set (the data associated with the task) and the request is fired off using the startService() method.
EditText input = (EditText) findViewById(R.id.txt_input); String strInputMsg = input.getText().toString(); Intent msgIntent = new Intent(this, SimpleIntentService.class); msgIntent.putExtra(SimpleIntentService.PARAM_IN_MSG, strInputMsg); startService(msgIntent);
Finally, define a BroadcastReceiver object for use by the application Activity, to listen for the results of each task completing and update the user interface accordingly:
public class ResponseReceiver extends BroadcastReceiver { public static final String ACTION_RESP = "com.mamlambo.intent.action.MESSAGE_PROCESSED"; @Override public void onReceive(Context context, Intent intent) { TextView result = (TextView) findViewById(R.id.txt_result); String text = intent.getStringExtra(SimpleIntentService.PARAM_OUT_MSG); result.setText(text); } }
The BroadcastReceiver class’s onReceive() callback method does the work of reacting to a new broadcast from your SimpleIntentService. It updates the TextView control based upon the Intent extra data, which is the “result” from the task processing.
Your application should register the broadcast receiver only when it needs to be listening for results, and then unregister it when it’s no longer needed. To manage this, first add a private member variable to your Activity, like this:
private ResponseReceiver receiver;
Activities typically register for broadcasts in their onCreate() or onResume() methods by creating an IntentFilter, like this:
IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP); filter.addCategory(Intent.CATEGORY_DEFAULT); receiver = new ResponseReceiver(); registerReceiver(receiver, filter);
Similarly, it is typical to unregister the receiver when the Activity class no longer needs to react to results. For example, in the onPause() or onDestroy() methods.
unregisterReceiver(receiver);
That’s the complete implementation of our example. The Activity shoots off requests to the SimpleIntentService. The service handles the queuing, processing, and broadcasting of the result of each task asynchronously. The service shuts itself down when there’s nothing left to do and starts to back up if a new request comes in. Meanwhile, the application Activity remains responsive because it is no longer processing each request on the same thread that handles the UI. The user interface is responsive throughout all processing, allowing the user to continue to use the application. The user can hit the Button control five times in succession and trigger five tasks to be sent to the IntentService without having to wait 5 seconds between each click.
Conclusion
Offloading work from the main UI thread is important for keeping your application responsive. The simple Service class called IntentService makes it very easy to offload application processing from the main UI thread to a simple, serial work queue. Setting up an IntentService is straightforward, making it ideal for situations when your Android application routinely needs to dispatch some task to be completed in the background.