Starting service multiple times will nest calls made in onStartCommand()? - android

I am calling startService() multiple times in my class.
there is a function in my service's onStartCommand(), like this -
Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(StaticValues.TAG, "service started.");
processItem();
return 0;
}
My question is, if I start service again, onStartComamnd() will be called again. So will this call wait till my previous call is over or it will execute both calls to processItem() parallelly?
Edit : Answer I found from links in comments
startService() is asynchronous. So while you are looping the calls, the service itself hasn't gotten any resources and didn't start yet.
The Service will only run in one instance. However, everytime you start the service, the onStartCommand() method is called.
Check : What happens if a Service is started multiple times?

A Service can only be started once, if you want to and love to complicate things use a boolean flag
Using startService() overrides the default service lifetime that is managed by bindService(Intent, ServiceConnection, int): it requires the service to remain running until stopService(Intent) is called, regardless of whether any clients are connected to it. Note that calls to startService() are not nesting: no matter how many times you call startService(), a single call to stopService(Intent) will stop it.
If the service is being started or is already running, the
ComponentName of the actual service that was started is returned; else
if the service does not exist null is returned.
Note that multiple calls to Context.startService() do not nest (though
they do result in multiple corresponding calls to onStartCommand()),
so no matter how many times it is started a service will be stopped
once Context.stopService() or stopSelf() is called;
Link to the Docs
Life Cycle of a Service

Related

What can I expect when onCreate() calls startService()

I am trying to understand the Service Life Cycle while working through some Android Open Source Code.
I was looking at a Service implementation which I distilled down to something like the following...
public class MyService extends Service {
public MyService() { super(); }
#Override
public void onCreate() {
super.onCreate();
init();
//==this seems odd to me
//comment in AOSP says startService() is called to make
//sure Service stays around long enough for the async call
//to complete.
startService(new Intent(this, myservice.class()));
doSomeMoreInitAsync();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if(actionableIntent(intent,flags,startId)) {
//do something
//NOTE: the Intent passed to startService() in onCreate()
//above will go around this block of code, doing nothing
//except returning START_STICKY
}
return START_STICKY;
}
public void onDestroy() {
//destroy stuff
}
#Override
public IBinder onBind(final Intent intent) {
return mBinder; //an instance of android.os.Binder derivative
// created when this service was instantiated
}
//other stuff
}
Why would someone want to have onCreate() call startService() on itself like above, doing nothing? The comment in code sheds some light, but it's like assumptions are being made about the Life Cycle that I don't understand. I.e., is it reasonable to expect onCreate() to effectively start its own service?
I know that if a service has already been started then onCreate() will only be called once (unless destroyed and restarted, then a new instance of the service is created and onCreate() is called once on it). My first concern with this example would be that there is an expectation placed upon the underlying Service API implementation that the Service is already in the initialized state before onCreate() is called (else there be an infinite recursion, but there is not).
But isn't onCreate() supposed to be part of the initialization (albeit an optional part for the subclass)?
Is this coding logic a reasonable way of making sure the Service is forced to be an Unbounded Service? Or am I looking at a bad example in the AOSP which may have undefined behavior in the future?
You are correct in that a Service will call onCreate and onStartCommand if it is started via Context.startService. So in this sense, when you return START_STICKY, the Service will continually run until an explicit call to stopService() is called. It will also be destroyed and restarted during this lifecycle.
Another way to create a Service, is by binding to it. As per the docs:
Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand().
So, it's possible for a Service to be created by simply binding to it. However, the lifecycle of a Service indicates that it will remain if it is started or a client is still bound to it. Meaning, that if it was created by a bind command, it will immediately be destroyed as soon as the client unbinds.
So, if a Service starts itself in the onCreate(), it will ensure that it puts itself in the started state regardless of whether it was created by binding or by an explicit call to startService. Since there's no actionable intent, the onStartCommand will just pass straight through. An clients that call startSevice will, presumably, have actionable Intents in which case the Service will perform its duties.

When is onStartCommand of a service executed

When is onStartCommand of a service exactly executed?
In the following code my service is started from the onCreate in my activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, CenseDroidService.class);
//onStartCommand is not extecuted immediatly after startService
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
So when does the Android system decide to call onStartCommand? All that I know is that is runs on the main thread some time after calling startService. The onCreate is fully executed before onStartCommand is called.
From the documentation.
Called by the system every time a client explicitly starts the service by calling startService(Intent), providing the arguments it supplied and a unique integer token representing the start request
What this means is, every time you call startService(intent) with an Intent, then onStartCommand will be called. If you have a hundred Activities that all need to start and bind to this service, then they will all call startService() and onStartCommand will be called.
Now when it is exactly called is a bit trickier to answer. It is sometime in the future which is why your ServiceConnection works asynchronously. Most likely it can be within the next UI Thread cycle, but it is not something you should rely on.
If you need a reasonable knowledge of when the Service started, you could use the LocalBroadcastManager to broadcast the event to all registered listeners. The LocalBroadcastManager#sendBroadcastSync will actually block until all listeners respond so it may be useful for this scenario.

When can a service be destroyed and where inserting the stopSelf() method?

I'm reading the official documentation about Services, but I'm a little bit confused because some things aren't so explicit.
Let's take this snippet:
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startID) {
while(...any condition...) {
//some actions
}
return START_SOMETHING;
}
public IBinder onBind(Intent intent) {
return null;
}
}
My doubts are the followings:
The Android system can destroy a service not bound to the current focused activity and not declared as in foreground. But can the Android system destroy a service even if it is still in the while loop?
When I call stopService() does it wait for the onStartCommand() to get to the return statement?
Where should I insert the stopSelf() call? Just before the return statement?
Can the Android system destroy a service even if it is still in the while loop?
Yes. For some reason, extreme low memory pressure (for example), Android system kills the Service without calling onDestroy() method. Why? Because of Service always runs on UI thread.
When I call stopService() does it wait for the onStartCommand() to get to the return statement?
No. Return statement's action will be executed when Android system kills the Service. But, if you call stopSelf() manually, the return statement's action will be ignored.
Where should I insert the stopSelf() call? Just before the return statement?
Call stopSelf() wherever and whenever you want. For example, if user press a button, call stopSelf() to stop the Service playing a music.

How to deal with a loop Service?

My Android application is activating a service that call an 'Activity.
On mainActivity:
startService(new Intent(getBaseContext(),MyService.class));
And then on service:
public int onStartCommand(Intent intent,int flage,int startId){
// Toast.makeText(this, "Yes please", Toast.LENGTH_LONG).show();
Intent mIntent=new Intent(MyService.this,trackingActivity.class);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
return START_STICKY; }
At the end of trackingActivity this line is written (Again):
startService(new Intent(getBaseContext(),MyService.class));
That's creates a lot of Services. Is there a better way to create a background service that repeats itself always without creating each time a new Service ?
I tried to do a while loop inside the Activity :
while(true){
Actions on activity
}
But with no success.
Context.startService(Intent) does not create a new Service for each call.
If there is already a matching service running, it passes the intent to that running service, but does not create a new one each time.
See the Android Developer Docs for Context.startService(Intent):
If this service is not already running, it will be instantiated and
started (creating a process for it if needed); if it is running then
it remains running.
Every call to this method will result in a corresponding call to the target service's onStartCommand(Intent, int, int) method, with the intent given here.
There is similar information in the Android Developer Docs about Starting a Service:
[When starting a service using an intent] 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().
...
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.

Foreground service killed when user swypes away

As the title says I am having the following problem. My foreground service is being killed when the activity that started it is swyped away from recent tasks list.
I am starting a service with
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(notificationID, notification);
return START_STICKY;
}
Can someone please tell me why is this happening and how can I make it so the service stays running when user swypes the activity away.
I don't have access to public void onTaskRemoved (Intent rootIntent) for some reason but I don't know what to do in that method anyway...
I am starting the service like this this and it's not a bound service
serviceIntent = new Intent(this, RecordingService.class);
startService(serviceIntent);
If little use case description helps I am trying to control sound recorder from a remote view in the notification bar so restarting a service is not an option since it should continue to record even if activity is destroyed.
BTW.I did tried starting a service in another process by android:process=":recordingProcess" and the service does continue to run then but I am suspecting this is not how you should do it.
Even i had the same issue and i had access to onTaskRemoved() function.Please check this link, "Process life cycle" topic.
Try to return from onStartCommand() START_REDELIVER_INTENT, service will get start again.
From Android Developer Reference
A service can be both started and have connections bound to it. In
such a case, the system will keep the service running as long as
either it is started or there are one or more connections to it with
the Context.BIND_AUTO_CREATE flag. Once neither of these situations
hold, the service's onDestroy() method is called and the service is
effectively terminated.
How are you starting your service?

Categories

Resources