Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bound service versus started service on Android and how to do both

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 call bindService() without starting the service?
  • Why does bindService() return true even if the service is not running? In this case it doesn't seem like the service has been started, based on Log calls.
  • If there the previous point is the correct/expected behavior of bindService(), is there a workaround (i.e. somehow ensure that startService 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.

like image 723
angelatlarge Avatar asked Apr 23 '13 05:04

angelatlarge


1 Answers

  1. If you bindService with 0 flag then the service will not start. You can bindService with BIND_AUTO_CREATE flag and if the service is not started, it will be started. However, when you unbindService the service will be destroy.
  2. bindService with 0 flag always returns true.
  3. You can always call startService. If the service is already running then a new service will not be created. The running service onStartCommand will be called.

There should not be any problem if you startService in onCreate and then bindService in onResume and unbindService in onPause.

like image 97
Hoan Nguyen Avatar answered Sep 20 '22 08:09

Hoan Nguyen