I am asking a vexed question that has been (partially, to my mind) addressed here and here. Let's say like in many examples we want to create a music application, using (say) a single activity and a service. We want the service to persist when the Activity is stopped or destroyed. This kind of lifecycle suggests a started service:
A service is "started" when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed
Ok, but we also want to be able to communicate with the service, so we need a service binding. No problem, we have both a bound and started service as this answer suggests:
- At activity startup (or some other point) we call startService()
- After that we call bindService() to obtain the IBinder interface, and proceed from there.
So far so good, but a problem arises from the fact that when the activity starts, we do not know if the service is around or not. It may have been started or it may not have been. The answer could be something like:
- At startup, try to bind to the service (use bindService() without the BIND_AUTO_CREATE flag)
- If that fails, then start the service using
startService()
, and then bind to it.
This idea is premised on a particular reading of the docs for bindService()
:
Connect to an application service, creating it if needed.
If zero flag means "service is not really needed" than we are OK. So we try something like this using the following code:
private void connectToService() {
Log.d("MainActivity", "Connecting to service");
// We try to bind to an existing service
Intent bindIntent = new Intent(this, AccelerometerLoggerService.class);
boolean bindResult = bindService(bindIntent, mConnection, 0);
if (bindResult) {
// Service existed, so we just bound to it
Log.d("MainActivity", "Found a pre-existing service and bound to it");
} else {
Log.d("MainActivity", "No pre-existing service starting one");
// Service did not exist so we must start it
Intent startIntent = new Intent(this, AccelerometerLoggerService.class);
ComponentName startResult = startService(startIntent);
if (startResult==null) {
Log.e("MainActivity", "Unable to start our service");
} else {
Log.d("MainActivity", "Started a service will bind");
// Now that the service is started, we can bind to it
bindService(bindIntent, mConnection, 0);
if (!bindResult) {
Log.e("MainActivity", "started a service and then failed to bind to it");
} else {
Log.d("MainActivity", "Successfully bound");
}
}
}
}
And what we get is a successful binding every time:
04-23 05:42:59.125: D/MainActivity(842): Connecting to service
04-23 05:42:59.125: D/MainActivity(842): Found a pre-existing service and bound to it
04-23 05:42:59.134: D/MainActivity(842): onCreate
The global question is "Am I misunderstanding bound versus started services and how to use them?" More specific questions are:
- Is it the correct understanding of the docs to think that zero flag passed to
bindService()
means "Do not start the service"? If not, is there no way to callbindService()
without starting the service? - Why does
bindService()
returntrue
even if the service is not running? In this case it doesn't seem like the service has been started, based onLog
calls. - If there the previous point is the correct/expected behavior of
bindService()
, is there a workaround (i.e. somehow ensure thatstartService
is called only if the service is not running?)
P.S. I've moved on from the problem in my own code: I issue startService()
calls regardless, since repeated startService()
are simply ignored. However, I would still like to understand the issues better.