Services, BroadcastReceivers and Notifications

In this lecture, we discuss a number of building blocks for MyRunds and any complex Android app:

Services: are part of the application and run on a different thread in the background and supports some long-running operation, such as, handling location updates from the LocationManager as in the case of MyRuns. Typically, services operate outside of the user interface.

Notification allows apps or services associated with an app to inform the user of an event.

Bound Services. A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses such as data.

As part of binding ServiceConnections are established between two components (i.e., the client and server). The connection allows both the client and service to exchange messages across the connection.

BroadcastReceivers are used to receive events that are announced by other components. For example, activities or other Android components can register for a specific BroadcastReceivers. Receivers that registers will receive intents when other components issue sendBroadcast().

What this lecture will teach you

Interacting with the status bar

Notify Demo: creates a service that notifies the status bar

Bind Demo: starts/stops and bing/unbinds to a service. A ServiceConnection is set up to exchange messages across the connection.

We will discus the command and the binding pattern.

Some hints to MyRuns4 are given in terms of design

Demo projects

The demo code used in this lecture include:

Notification examples:

We will use the notifydemo.zip app to demonstrate how to interact with the status bar. This demo is a slighted modified version from here.

Service examples:

CommandPattern: Here is a simple started service example that implements the command pattern CommandPattern.zip. The app simply starts a service on a worker thread to download the Dartmouth ORC. The service sends a broadcast when the download is complete. The UI thread then allows the user to enter a new command. If you removed the enable/disable on the button you could load multiple commands into the service.

BindingPattern: Here is binding service example that implements the binding pattern BinddingPattern.zip. Sample downloader example as the command pattern but no feed back to the UI to enable the button. You can post a runnable on the widget from the worker thread to do this. Try it.

BindingPatter with messaging: We use the BindDemo.zip app to demonstrate how to an activity binds to a service and them interacts through a connection. The binding demo comes from stackoverflow. This example provides a general client server interface. The service can support multiple clients. It uses messaging and handlers on either side of the connection. Very cool. Understand it.

Big MyRuns4 Hinteroo

There are many ways to implement the coordination between MapDisplayActivity and a service that handles new Location objects and another service that handles new activity updates. You can use any of the service patterns discussed in the notes and the code snippet examples. The easest approach is:

one service for passing new Location objects to the MapDisplayActivity using a BroadcastReceiver; and

another service for passing new activity updates to the MapDisplayActivity using another BroadcastReceiver.

Note, the Location object is a parcelable object so you can pass it using an Intent as an extra when you send the broadcast from the service to the activity. You have to use getParcelableExtra(String name) at the receive().

But you could use the BindingPattern, CommandPattern or BindDemo (with messaging -- more complex but fun).

The design up to you. Have fun!

Interacting with the status bar

Android supports a number of different ways to inform the user including:

Staus bar at the top of the UI, owned and managed by the Android system but apps can display messages or icon in the notification area.

Play sounds, uses lights and vibrate the phone to inform the user of an app related event

Notification tray or drawer which allows the app to present more information and certain control elements such as navigating back to the main app, that is, bring the app back into focus if its paused.

We will focus on the status bar notification in this lecture. You will need to implement this type of notification for MyRuns4.

Typically a programmer develops an app and needs to inform the user of an event that is outside of the normal UI. For example if we consider MyRuns4 that you are coding right now. When the user starts an exercise using the GPS mode (or automatic) the code creates a service to process location updates. When this service starts on an independent thread in the background it informs the user that it is running by display first message (i.e., "MyRuns is recording your path" ) and then an icon (i.e., the D icon) in the notification area. We can see this below

To see the details of the MyRuns4 notification, the user needs to wipe down on the status bar (i.e., notification area) to open the notification drawer. The system controls the notification area and drawer and allows the user to view and interact with it at any point. For example, in the case of MyRuns4 notification in the drawer the user can wipe down the status bar and click on the MyRuns notification in the drawer and it bring the app back into focus, as shown in the image below.

Notify demo app

The simple notification app used in this lecture uses the status bar to inform the user that a service has been started (we will discuss services next). When the user starts the service an icon is displayed in the status bar. If you wipe down the status bar you will see that the notification drawer for the service displays an icon and text (i.e., Demo of Notification! course website). If you click on this notification the service will launch a browser to display the class webpage.

When the app starts up there is no service running and nothing in the status bar associated with the notify app, as shown below.

When the user starts the service the icon shows up in the status bar or notification area, as shown in the image below.

The user can wipe down the status bar and click on the notification which triggers the service to start the browser with the course page, as illustrated in the digram below.

In addition, the user could mindlessly ;-) start and stop the service and see the icon come and go -- be mindless, just do it.

This simple application introduces a number of new things. Importantly a background service is started to interact with the status bar. In MyRuns4 we will implement a service to manage location updated from the LocationManager.

Let's look at the code.

Notify activity

The activity simply takes input from the user and starts and stops the service.

Service Lifecycle

There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.

For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.

Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service's IBinder). Usually the IBinder returned is for a complex interface that has been written in Android Interface Definition Language (AIDL).

A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().

Notify Service

The activity starts and stops in the service. A broadcast is used to stop the service; that is, the activity sends an intent to all interested BroadcastReceivers with stop command. In our example, on the service is listening on this broadcast and implements a BroadcastReceiver

BindDemo app: Binding to a client to a service

In this application the activity binds to a service and creates a ServiceConnection that is used to exchange messages between the activity and service. The activity creates and stops the service based on user input as well as binds and unbinds from the service. The user can input a increment value which is send to the server and reflected in the UI.

BindDemo Design

In the design diagram shown below shows the key component and interactions for the BindDemo app. The key components are the client and the service. The UI allows the user to star and stop the service, and allow the client to bind and unbind to the service using buttons.

The status on the UI shows the state of the binding: attached, unbinding. The count field shows the value of the count sent periodically via a message from the service to the client, as shown below

The client-service communicate via a serviceConnection. Messaging flows in both directions. The client can register (MSG_REGISTER_VALUE) to receive count values (MSG_SET_INT_VALUE) from the service over the

Note, when the client calls bindService() the onBind() method in the service returns the IBinder object. The IBinder is returned to the client's onServiceConnected(). This interaction is not obvious when reading the code. The service is used to send msgs to the service as shown in onServiceConnected() below.