Services can be used by any application component that hangs around for a reasonable period of time. This includes activities, content providers, and other services. Notably, it does not include pure broadcast receivers (i.e., intent receivers that are not part of an activity), since those will get garbage collected immediately after each instance processes one incoming Intent
.
To use a local service, you need to start the service, get access to the service object, and then call methods on that service. You can then stop the service when you are finished with it, or perhaps let the service stop itself. In this chapter, we will look at the client side of the Service/WeatherPlus
sample application. The WeatherPlus
activity looks a lot like the original Weather
application. It's just a web page showing a weather forecast, as shown in Figure 30–1.
Figure 30–1. The WeatherPlus service client
To start a service, one approach is to simply call startService()
, providing the Intent
specifying the service to start (again, the easiest way is probably to specify the service class, if it's your own service). Conversely, to stop a service started via startService()
, call stopService()
with the Intent
you used in the corresponding startService()
call.
Once the service is started, you need to communicate with it. It could be that all the communication you need can be via the extras you package in the Intent
. Or, if it is a local service that offers a singleton, you can reference the singleton.
However, if you implemented onBind()
as shown in the previous chapter, there is a different way to get at the service: through bindService()
.
When an activity binds to a service, it primarily is requesting to be able to access the public API exposed by that service via the service's binder, as returned by the service's onBind()
method. When doing this, the activity can also indicate, via the BIND_AUTO_CREATE
flag, to have Android automatically start up the service if it is not already running.
To use this technique with our WeatherPlus
and WeatherPlusService
classes, we first need to make a call to bindService()
from onCreate()
:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
browser=(WebView)findViewById(R.id.webkit);
bindService(new Intent(this, WeatherPlusService.class),
onService, Context.BIND_AUTO_CREATE);
}
This bindService()
call refers to an onService
callback object, an instance of ServiceConnection
:
private ServiceConnection onService=new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService=((WeatherPlusService.LocalBinder)rawBinder).getService();
}
public void onServiceDisconnected(ComponentName className) {
appService=null;
}
};
Our onService
object will be called with onServiceConnected()
as soon as the WeatherPlusService
is up and running. We are given an IBinder
object, which is an opaque handle representing the service. We can use that to obtain the LocalBinder
exposed by the WeatherPlusService
, and from there to get the actual WeatherPlusService
object itself, held as a private data member:
private WeatherPlusService appService=null;
We can then call methods on the WeatherPlusService
, such as a call to get the forecast page when needed:
private void updateForecast() {
try {
String page=appService.getForecastPage();
browser.loadDataWithBaseURL(null, page, "text/html",
"UTF-8", null);
}
catch (final Throwable t) {
goBlooey(t);
}
}
We also need to call unbindService()
from onDestroy()
, to release our binding to WeatherPlusService
:
@Override
public void onDestroy() {
super.onDestroy();
unbindService(onService);
}
If there are no other bound clients to the service, Android will shut down the service as well, releasing its memory. Hence, we do not need to call stopService()
ourselves, because Android handles that, if needed, as a side effect of unbinding.
This is a fair bit more code than simply using a public static singleton for the service object. However, this approach is less likely to result in memory leaks.
So to recap:
bindService()
with BIND_AUTO_CREATE
(if you wish to communicate via the binding mechanism) or startService()
.unbindService()
or stopService()
.Another possibility for stopping a service is to have the service call stopSelf()
on itself. You might do this if you use startService()
to have a service begin running and do some work on a background thread, so the service will stop itself when that background work is completed.
In the preceding chapter, you saw how the service sends a broadcast to let the WeatherPlus
activity know a change was made to the forecast based on movement. Now, you'll see how the activity receives and uses that broadcast.
Here are the implementations of onResume()
and onPause()
for WeatherPlus
:
@Override
public void onResume() {
super.onResume();
registerReceiver(receiver,
new IntentFilter(WeatherPlusService.BROADCAST_ACTION));
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
In onResume()
, we register a static BroadcastReceiver
to receive Intent
s matching the action declared by the service. In onPause()
, we disable that BroadcastReceiver
, since we will not be receiving any such Intent
s while paused.
The BroadcastReceiver
, in turn, simply arranges to update the forecast:
private BroadcastReceiver receiver=new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
updateForecast();
}
};
3.139.97.202