132

If I have the following code:

Intent intent = new Intent(this,DownloadService.class);     
for(int i=0;i<filesArray.length;i++){        
     startService(intent);          
}

In this code DownloadService extends IntentService.

So now when I'm calling startService(intent) does that mean that I'm starting a new service every time startService(intent) is called or does that mean that DownloadService is run once and then each time I call startService(intent) it will just pass a different intent with a different startId.

Does this make sense, and which one of these is the case ?

Siddharth
  • 9,349
  • 16
  • 86
  • 148
bytebiscuit
  • 3,446
  • 10
  • 33
  • 53

5 Answers5

186

The Service will only run in one instance. However, everytime you start the service, the onStartCommand() method is called.

This is documented here

Novin Shahroudi
  • 620
  • 8
  • 18
Philipp Wendt
  • 2,538
  • 1
  • 15
  • 17
  • 1
    Thanks. It also says there: "The startService() method returns immediately and the Android system calls the service's onStartCommand() method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand()." So if the service is already running then the system will skip the onCreate() method and call onStartCommand() only or what ? – bytebiscuit Nov 05 '11 at 11:44
  • I don't really know, but I am pretty sure that is the case (makes a lot of sence not to call `onCreate()` if the service is already created). It should be easy to determine if you put a `Log.i()` in both of the callbacks and check the LogCat. – Philipp Wendt Nov 05 '11 at 11:50
  • Just did that... and strangely enough it starts the onCreate after the last startService() call!!! – bytebiscuit Nov 05 '11 at 11:54
  • 16
    That is because `startService()` is asynchronous. So while you are looping the calls, the service itself hasn't gotten any resources and didn't start yet. – Philipp Wendt Nov 05 '11 at 11:59
  • that doesn't make sense, asynchronous and as a sevice it should start in separate thread right away – neelabh Jan 05 '16 at 13:13
  • 1
    @neelabh not "right away", it takes some time to start the service, and the "for" loop would be still running and calling again and again the service, so the first tries wouldn't find any service running yet... so the method startService() would be called a couple of times, until service startup is complete. Please excuse my bad english. – mzalazar Apr 07 '16 at 00:38
29

Absolutely Correct. Only one instance of Service is created for an application process. And when you call StartService(); again, then only onStartCommand() gets called and new Intent is passed to onStartCommand() method.

Note: onCreate() is not called again.

About calling bindService() multiple times:

When you call bindService() multiple times, then again only one instance is used for Service and Android Runtime returns same IBinder object to client.

Means, onBind() is not called multiple times. And just cached IBinder object is returned.

Anish Mittal
  • 1,157
  • 12
  • 29
  • Does `onStop()` have to be called for every corresponding `onStartCommand`? – IgorGanapolsky Jul 01 '16 at 14:13
  • 8
    @IgorGanapolsky : First of all,There is no such callback method onStop() in Service. We need to call stopService() or stopSelf() to stop a service. And when the onStartCommand() has been called multiple times for multiple intents, then we need to call just stopSelf() or stopService() only once. If using IntentService, you should call stopSelfResult(int id) passing start id of request from onHandleIntent(), which will stop corresponding start id request, that was placed in work queue of IntentService. Hope this helps. – Anish Mittal Jul 01 '16 at 16:48
10

Adding some more information to the above answers which may be helpful for others is that, startId that the onStartCommand() method receives is different for every startService() call.

Also if we write in for loop as mentioned above, code written in onHandleIntent() would execute so many times as defined by the for loop frequency, but in sequence and not in parallel.

The concept is IntentService creates a work queue and each request to startService() trigger onStartCommand() which in turn stores the intent in work queue and then pass the intent one by one to onHandleIntent().

Rohit
  • 2,646
  • 6
  • 27
  • 52
Rahul Gupta
  • 219
  • 3
  • 8
3

According to the doc:

The startService() method returns immediately, and the Android system calls the service's onStartCommand() method. If the service isn't already running, the system first calls onCreate(), and then it calls onStartCommand().

and

Multiple requests to start the service result in multiple corresponding calls to the service's onStartCommand(). However, only one request to stop the service (with stopSelf() or stopService()) is required to stop it.

amrezzd
  • 1,787
  • 15
  • 38
0

Very helpful comments from Android official docs:

(highlighted by me)

If your service handles multiple requests to onStartCommand() concurrently, you shouldn't stop the service when you're done processing a start request, as you might have received a new start request (stopping at the end of the first request would terminate the second one). To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of the start request (the startId delivered to onStartCommand()) to which your stop request corresponds. Then, if the service receives a new start request before you are able to call stopSelf(int), the ID doesn't match and the service doesn't stop.

starriet
  • 2,565
  • 22
  • 23