Listening in with broadcast receivers Another way to use an Intent involves sending a broadcast to any interested receiver.

4.2 Listening in with broadcast receivers Another way to use an Intent involves sending a broadcast to any interested receiver.

There are many reasons an application may want to broadcast an event; for example, when an incoming phone call or text message is received. In this section we will take a look at how events are broadcast and how they are captured using a BroadcastReceiver.

Here we will continue working through the WeatherReporter sample application we began in the previous section. One of the most important parts of the Weather- Reporter application will be its ability to display alerts to the user when severe weather is in the forecast for a location where the user has indicated interest. We will need a background process that checks the weather and sends any needed alerts. This is where the Android Service concept will come into play. We won’t be creating the actual Service class until section 4.3, but we need a way to get the platform running the Service as soon as it boots up, and this is where we will use an Intent broadcast.

4.2.1 Overloading the Intent concept As you have seen, Intent objects are used to go from Activity to Activity in an

Android application. While this is the main use of intents in Android, it is not the only one. Intents are also used to broadcast events to any configured receiver using one of several methods available from the Context class, as shown in table 4.3.

Table 4.3 Methods for broadcasting intents

Method

Description

sendBroadcast(Intent intent) Simple form for broadcasting an Intent . sendBroadcast(Intent intent, String Broadcasts an Intent with a permission String

receiverPermission) that receivers must declare to receive the broadcast.

Listening in with broadcast receivers

Table 4.3 Methods for broadcasting intents (continued) Method

Description sendStickyBroadcast(Intent intent) Broadcasts an Intent that hangs around a short

time after it is sent so that receivers can retrieve data. Applications using this must declare the BROADCAST_STICKY permission.

sendOrderedBroadcast(Intent Broadcasts an Intent call to the receivers one- intent, String receiverPermission) by-one serially.

sendOrderedBroadcast(Intent Broadcasts an Intent and gets a response back intent, String receiverPermission, by implementing your own BroadcastReceiver BroadcastReceiver resultReceiver, for the broadcast (and passing it in). All receivers Handler scheduler, int initialCode, can append data that will be returned in the String initialData, Bundle BroadcastReceiver . When using this method,

initialExtras) the receivers are called serially.

When broadcasting intents you are basically reusing the Intent concept to send an event in the background. Though the Intent class is used, it is used differently than when invoking foreground Activity paths. A broadcast Intent does not invoke an Activity (though a BroadcastReceiver can do so after the event is received, if necessary).

Another important aspect with Intent broadcasts is how permissions are handled. When you broadcast an Intent, you can optionally specify a permission. Permissions are something we addressed in chapter 1. They basically are String declarations that can

be used when making a broadcast that require receivers to declare the same permission.

Broadcasting an Intent itself is fairly straightforward; you use the Context object to throw it on the wire, and interested receivers will catch it. Android provides a set of platform-related Intent broadcasts that use this approach. When the time zone on the platform changes, when the device completes booting, or when a package is added or removed, for example, the system broadcasts an event using an Intent. Some of the specific Intent broadcasts the platform provides are shown in table 4.4.

Table 4.4 Provided Android platform broadcast actions

Description ACTION_TIME_TICK

Action

Sent every minute to indicate that time is ticking ACTION_TIME_CHANGED

Sent when the user changes the time on the device ACTION_TIMEZONE_CHANGED

Sent when the user changes the time zone on the device ACTION_BOOT_COMPLETED

Sent when the platform completes booting ACTION_PACKAGE_ADDED

Sent when a package is added to the platform ACTION_PACKAGE_REMOVED

Sent when a package is removed from the platform ACTION_BATTERY_CHANGED

Sent when the battery charge level or charging state changes

C HAPTER 4 Intents and services

The other half of broadcasting events is the receiving end. To register to receive an Intent broadcast, you implement a BroadcastReceiver. This is where we are going to implement a receiver that will catch the platform-provided BOOT_COMPLETED Intent in order to start the weather alert service we will create for the Weather- Reporter application.

4.2.2 Creating a receiver Because the weather alert Service we want to create needs to be running in the back-

ground whenever the platform itself is running, we need a way to start it when the platform boots. To do this, we will create a BroadcastReceiver that listens for the BOOT_COMPLETED Intent broadcast.

The BroadcastReceiver base class provides a series of methods that allow for get- ting and setting a result code, result data (in the form of a String), and an extras Bun- dle . In addition, there are a series of lifecycle-related methods that correspond to the lifecycle events of a receiver; you will learn more about these as we progress through this section.

Associating a BroadcastReceiver with an IntentFilter can be done in code or in the manifest XML file. Once again the XML usage is often easier and thus more com- mon. This is the way we did it for WeatherReporter in listing 4.3, where we associated the BOOT_COMPLETED broadcast with the WeatherAlertServiceReceiver class. This class is shown in listing 4.5.

Listing 4.5 The WeatherAlertServiceReceiver BroadcastReceiver class

public class WeatherAlertServiceReceiver extends BroadcastReceiver { @Override

public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { context.startService(new Intent(context,

WeatherAlertService.class));

Override

onReceive C

Start WeatherAlertService D Extend BroadcastReceiver B

} When creating your own Intent broadcast receiver you extend the BroadcastRe-

ceiver class Android provides B and implement the abstract onReceive(Context c, Intent i) method C . Within this method we are starting the WeatherAlertService.

This Service class, which we will create next, is started using the Context.start- Service(Intent

i, Bundle b) method D .

Keep in mind that receiver class instances have a very short, specific lifecycle. When the onReceive(Context c, Intent i) method is complete, the instance and process that invoked the receiver are no longer needed and may be killed by the system. Because of this, you can’t perform any asynchronous operations in a BroadcastReceiver, such as binding to a Service or showing a dialog. Alternatively, you can start a Service, as we have done here, and leave it running in the background. (Binding to a Service is different than starting one; we will cover this distinction in the next section.)

Building a Service

Now that our receiver is starting the WeatherAlertService, which will run in the background and warn users of severe weather in the forecast with a Notification- based alert, we need to delve into the realm of the Android Service concept itself.