• No results found

Checking the weather with broadcast receivers

Intents and Services

4.3 Checking the weather with broadcast receivers

So far you’ve seen how to use an Intent to communicate within your app and to issue a request that another component will handle. You can also send an Intent to any interested receiver. When you do, you aren’t requesting the execution of a specific task, but instead you’re letting everyone know about something interesting that has happened. Android already sends these broadcasts for several reasons, such as when an incoming phone call or text message is received. In this section, we’ll look at how events are broadcast and how they’re captured using a BroadcastReceiver.

We’ll continue to work through the WeatherReporter sample application we began in section 4.2. The WeatherReporter application will display alerts to the user when severe weather is forecast for the user’s indicated location. We’ll 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 need to start the Service when the device boots, so we’ll listen for the boot through an Intent broadcast.

4.3.1 Broadcasting Intent

As you’ve seen, Intent objects let you move from Activity to Activity in an Android application, or from one application to another. Intents can also 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(Intentintent) Simple form for broadcasting an Intent.

sendBroadcast(Intentintent, StringreceiverPermission)

Broadcasts an Intent with a permission String

that receivers must declare in order to receive the broadcast.

sendOrderedBroadcast(Intentintent, StringreceiverPermission)

Broadcasts an Intent call to the receivers one-by- one serially, stopping after a receiver consumes the message.

When you broadcast Intents, you send an event into the background. A broadcast Intent doesn’t invoke an Activity, so your current screen usually remains in the foreground.

You can also optionally specify a permission when you broadcast an Intent. Only receivers who’ve declared that permission will receive the broadcast; all others will remain unaware of it. You can use this mechanism to ensure that only certain trusted applications can listen in on what your app does. You can review permission declara- tions in chapter 1.

Broadcasting an Intent is fairly straightforward; you use the Context object to send it, and interested receivers catch it. Android provides a set of platform-related Intent broadcasts that use this approach. In certain situations, such as when the time zone on the platform changes, when the device completes booting, or when a package is added or removed, the system broadcasts an event using an Intent. Table 4.4 shows some of the specific Intent broadcasts the platform provides.

To register to receive an Intent broadcast, you implement a BroadcastReceiver. You’ll make your own implementation to catch the platform-provided BOOT_ COMPLETEDIntent to start the weather alert service.

sendOrderedBroadcast(Intentintent, StringreceiverPermission,

BroadcastReceiverresultReceiver, Handlerscheduler,intinitialCode, String initialData,

BundleinitialExtras)

Broadcasts an Intent and gets a response back through the provided BroadcastReceiver. All receivers can append data that will be returned in the

BroadcastReceiver. When you use this method, the receivers are called serially.

sendStickyBroadcast(Intentintent) Broadcasts an Intent that remains a short time after broadcast so that receivers can retrieve data. Applications using this method must declare the

BROADCAST_STICKY permission.

Table 4.4 Broadcast actions provided by the Android platform

Action Description

ACTION_BATTERY_CHANGED Sent when the battery charge level or charging state changes

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_TIME_CHANGED Sent when the user changes the time on the device

ACTION_TIME_TICK Sent every minute to indicate that time is ticking

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

Table 4.3 Methods for broadcasting intents (continued)

115

Building a background weather service

4.3.2 Creating a receiver

Because the weather alert Service you’re going to create should always run in the background, you need a way to start it when the platform boots. To do this, you’ll cre- ate a BroadcastReceiver that listens for the BOOT_COMPLETEDIntent broadcast.

The BroadcastReceiver base class provides a series of methods that lets you get and set a result code, result data (in the form of a String), and an extra Bundle. It also defines a lifecycle-related method to run when the appropriate Intent is received.

You can associate a BroadcastReceiver with an IntentFilter in code or in the manifest XML file. We declared this for the WeatherReporter manifest in listing 4.3, where we associated the BOOT_COMPLETED broadcast with the WeatherAlert- ServiceReceiver class. This class is shown in the following listing.

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)); } } }

When you create your own Intent broadcast receiver, you extend the Broadcast- Receiver class and implement the abstract onReceive(Contextc,Intenti) method. In our implementation, we start the WeatherAlertService. This Service class, which we’ll create next, is started using the Context.startService(Intent i, Bundle b) method.

Keep in mind that receiver class instances have a short and focused lifecycle. After completing the onReceive(Contextc,Intenti) method, the instance and process that invoked the receiver are no longer needed and might be killed by the system. For this reason, you can’t perform any asynchronous operations in a BroadcastReceiver, such as starting a thread or showing a dialog. Instead, you can start a Service, as we’ve done in listing 4.5, and use it to do work.

Our receiver has started the WeatherAlertService, which will run in the back- ground and warn users of severe weather in the forecast with a Notification-based alert. Let’s look more deeply into the concept of an Android Service.