9

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:

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.

Community
  • 1
  • 1
angelatlarge
  • 4,086
  • 2
  • 19
  • 36
  • I don't fully understand how this works, but [this](http://www.101apps.co.za/articles/bound-services-what-you-should-know.html) and [this](http://www.101apps.co.za/articles/binding-to-a-service-a-tutorial.html) may help you. – Ivan Black May 27 '15 at 14:11

1 Answers1

2
  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.

Hoan Nguyen
  • 18,033
  • 3
  • 50
  • 54
  • I thought that this was problematic as well, since your activity is destroyed if the user presses Back. In our music player example, we would want the music to continue playing once the user hit play, even if they do press Back. – angelatlarge Apr 23 '13 at 20:07
  • As long as you do not call stopService your music should continue playing – Hoan Nguyen Apr 23 '13 at 20:28
  • But then next time the Activity is shown, `startService()` will be called from `onCreate()`, and we are back to the same issue. – angelatlarge Apr 23 '13 at 20:30
  • I do not quite understand your question. As I understand you want to know if the service is running or not. Why do you want to know that? Do you pass an intent to the service when you call startService? – Hoan Nguyen Apr 24 '13 at 00:54
  • Sorry for being obtuse. Partly I am trying to understand how Android service system is supposed to work. I've tried to edit the question to mention the specific questions I have. – angelatlarge Apr 24 '13 at 18:53
  • How can `bindService` return true and be consistent with this in the docs "If you have successfully bound to the service, true is returned;" - can you bind to a service that hasn't been started? How does that work? – angelatlarge Apr 24 '13 at 19:16
  • I think but I am not sure that if you bind with flag 0, when you call startService you will automatically bind – Hoan Nguyen Apr 24 '13 at 19:24
  • I can now confirm that if you call bindService with 0 flag then call startService then you will be bind to the service without having to call bindService again. – Hoan Nguyen Apr 24 '13 at 19:29
  • @HoanNguyen I have a started service which I later bind it to an activity(same activity which started the service). I use the service instance from IBinder to call a function in the service to play songs,etc. When I press the back button the song stops, the service doesn't. Why does the song stop? Thank you. – Amit0191 Mar 07 '16 at 07:45
  • You have to post a question with your code as there are many things that can happen and without code it is impossible to answer. – Hoan Nguyen Mar 07 '16 at 20:36