StopService does not call onDestroy immediately - android

I am using the following statement to stop a download service (that extends IntentService) running in the background:
context.stopService(intent);
But this statement is not calling the onDestory() method of service immediately, It is taking sometime to call onDestroy() method of service.
#Override
public void onDestroy() {
Log.d("JSLog", "on destroy called");
super.onDestroy();
}
What should I do that after hitting the stopService() statement, it should immediately called onDestroy() method of the service.

In my case, I followed the tutorial at Android Developers, which uses a ServiceConnection. In the example code, they call unbindService() but never stopService(). So I added a call to stopService() to stop it, but still onDestroy() never got called.
From the documentation of Context.stopService():
Note that if a stopped service still has ServiceConnection objects bound to it with the BIND_AUTO_CREATE set, it will not be destroyed until all of these bindings are removed.
I interpreted this as it's okay to call stopService() or stopSelf() first, and then unbindService() afterwards (I'm using BIND_AUTO_CREATE) - and that the service would be stopped/destroyed upon calling unbindService().
But it turns out that this isn't the case. When I moved things around so that I'm calling unbindService() first and stopService() after that, my onDestroy() gets called immediately.

the intentService has new Thread,when u stop the service the new thread won't stop right now,if u want stop the thread right now ,i will extends service and new Thread in the service,when u need stop the service just need interrupt the thread.

This is expected behaviour, a Service won't immediately be destroyed once stopped just like an Activity might not be immediately destroyed once finished (unless you finish inside onCreate).

Related

Does stopSelf() guarantee Service stopping (and HOW)? if so, is return required (in case stopSelf called internally)?

My question concern Service and IntentService. The questions are as follows.
Does calling stopSelf() somewhere in Service (or IntentService) guarantee service to stop?
And (in case stopSelf() is called from in the Service) does a return statement mandatory to not execute code after stopSelf() call?
As I know, calling stopSelf() can stop code execution in case it throws an exception, else I can't find a logic for that.
Does calling stopSelf() somewhere in Service (or IntentService) guarantee service to stop?
Yes, it does.
And does a return statement mandatory to not execute code after stopSelf() call?
return is still needed if the function has a return type other than void (otherwise your code won't compile). The return statement most likely will be executed as stopSelf() results in stopping Service asynchronously.
As I know, calling stopSelf() can stop code execution in case it throws an exception, else I can't find a logic for that.
By calling stopSelf() you notify the system that Service is done with its "job" so the system could release resources the Service is holding. This is very similar to execution of Activity's onBackPressed() that is called when user presses the back button - the system finishes the Activity releasing resources.

How to handle service stopped in background

My ex colleague developed a service which plays music in background. However if user wants to exit from program then application calls below code to stop service. Service stops but i cannot handle it while overriding onDestroy method
Activity realAct = context.getParent();
if (realAct == null) {
realAct = context;
}
ContextWrapper cw = new ContextWrapper(realAct);
cw.stopService(new Intent(cw, MyPlayerService.class));
edit:
Briefly, Activity Main starts Activity Sub then Activity Sub starts Service. Then i press back button so Activity Sub finishes. When i am in Activity Main I call above stopservice code. So onDestroy method of Service is not called
Try again to use method like that in code of your service :
#Override
public void onDestroy()
{
super.onDestroy();
//your code
}
It has to work !
Are you trying to stop the service when the user exits from application?
onDestroy is called when system needs to kill activities due to insufficient resources. Just because you pressed back on your app doesn't mean onDestroy gets called immediately.
But if you want to force close your app to have it automatically invoke onDestroy, call
finish()
on wherever you are exiting your application from.
If you want to invoke onDestroy upon user pressing back button to exit, Override onBackPressed() and invoke finish() from there.
But really, this is an antipattern so I'd recommend using onPause() instead.
Edit Upon OP Edit:
I think we need to have more details on how you are instantiating the service but here are some additional thoughts:
Have you overridden onDestroy properly and calling the super method?
If this is the case, the only other possibility I can think of is that you still have ServiceConnection objects bound to the service with BIND_AUTO_CREATE set. Until all of these bindings are removed, service will not get destroyed.
So make sure to do both:
unbindService(conn);
stopService(intent);

Prevent an Android service from getting destroyed after an unbind

I have a scenario where an activity starts a service by invoking the startService method: both the Activity and the Service are in the same package. Then the service, according to its configuration parameters, could launch an activity (Let's call it ExternalActivity) contained in a different package: this activity bind the service through bindService; once this activity has finished its tasks, it calls the unbindService method as follows...
// method of ExternalActivity
#Override
public void onDestroy() {
super.onDestroy();
unbindService(...);
}
As a consequence, the service is also destroyed.
Is there the possibility of avoiding the destruction of the service?
As a consequence, the service is also destroyed.
As yorkw explained, a service is destroyed only when both of the following are true:
All calls to bindService() have been matched by corresponding calls to unbindService().
If somebody called startService(), somebody also called stopService() or the service called stopSelf().
Is there the possibility of avoiding the destruction of the service?
Find a better time to call stopService() or stopSelf(), whichever of those you are using.

Prevent multiple copies of an Android service

The doco for startService states "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."
I'm finding that each call to startService appears to be starting a separate instance of the service, in that the work that the service is doing (in my test case, trivially writing to a new log file) is being done again for each call.
I'm trying to detect the service by looping through ActivityManager... getRunningServices(Integer.MAX_VALUE)) but it's not showing up.
Android 2.3.3 on SGS 11
I'm missing something here. I understood that the Service's onCreate() method only gets called when it's created, and that since I have a continuous process running in the Service (the
In my Activity's onResume method I'm starting the service ("myService")with:
Intent intent = new Intent(this, myService.class);
startService(intent);
In MyService I have an onCreate like
#Override
public void onCreate(){
super.onCreate();
...
from where I set a timer, using a TimerTask, which writes to a log file once/second.
This works as expected - I can see the log being written.
In the Activity's onResume method, before calling the StartService method, I'm checking to see if the myService service exists by calling a checkForRunningService method containing
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (service.service.getClassName().contentEquals("com.gpsanimator.startrax.myService")) {
Toast.makeText(getApplicationContext(), "Service IS SO running: ", Toast.LENGTH_SHORT).show();
return true;
}
This never finds the myService service, even though it appears to be running as it's happily writing to the log file.
Eeach time I resume my Activity, the onCreate method of my myService service gets called - it generates a new log file and starts writing to it as well as the original log file being continuously updated.
Doesn't the Service get started the first time the startService is called? And then continue running? Shouldn't subsequent calls to startService() find the Service already running and therefore not trigger the onCreate() method again? But that's not what I'm seeing. It seems that every call to startService() is triggering the Service's onCreate() method.
It's obviously more complicated than this, and I would like to get to the bottom of it.
It all depends on which method you're putting the code in.
When you call startService only one service will be created at a given time. If the service already exists it will be reused. So the code in onCreate() will only be called if a service did not already exist.
However, each time you call startService the code in onStartCommand() will be run no matter what.
So yes only one instance of a service ever exists at a given time, but calling startService can have an effect.
The problem was I had declared my myService class to extend IntentService, not Service!
Once I fixed that, it all worked as per the book!
IntentService stops immediately (automatically) after work is performed, BUT if you start it again till work finishes you are reused existing service instance and onCreate isn't called. So please be careful with IntentServices.
You are extending IntentService which will work as a worker thread. The service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work. So in your case your service stop itself after completing the task so it creates multiple times. You should use Service class and bind with the component.

Android: service destroyed when display is rotated

I've got a service that is running in a separate process. I'm finding that after the main process UI thread exits from onDestroy() that my service is being destroyed even though I've provided the application context with the binding and specified BIND_AUTO_CREATE.
In my main process' UI thread onCreate() I've got this binding code:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
In my main process' UI thread onDestroy() I've got this unbinding code:
mAppContext.unbindService(mMyServiceConnection);
Note that I never call stopService().
Android's documentation for bindService() says:
The service will be considered required by the system only for as long as the calling context exists.
If I'm reading that correctly, because I supplied the application's context, the service is considered required by the system for the life of the application.
I have thought that maybe the application's context dies with onDestroy(). This is what Android's documentation says for getApplicationContext():
Return the context of the single, global Application object of the current process.
If the application's context dies with onDestroy(), then I think Android has a big issue. The issue is that when the display is rotated, onDestroy() is called (and immediately followed by onCreate()). Thus the effect is that when the display is rotated -- and it occurs quite frequently in my case! -- my service always exits.
Note that the pid of my app's process never changes, i.e. it is the same process. That is important in light of the documentation for getApplicationContext() stating "current process."
Here are what my debug logs show:
04-03 05:15:12.874: DEBUG/MyApp(841): main onDestroy
04-03 05:15:12.895: DEBUG/MyApp(847): service onUnbind
04-03 05:15:12.895: DEBUG/MyApp(847): service onDestroy
04-03 05:15:12.934: DEBUG/MyApp(841): main onCreate
04-03 05:15:12.966: DEBUG/MyApp(847): service onCreate
04-03 05:15:12.975: DEBUG/MyApp(847): service onBind
So my questions are:
1) Is my understanding about binding/unbinding correct?
2) Is there a way to have my service not get destroyed when UI thread's onDestroy() is called?
A hack for question #2 is to never unbind. But I don't like it because then I am leaking a binding every time onDestroy() is called. I could "remember" that I've got one leaked binding, and leak just that one, but then I've got cascaded hacks and it's real ugly.
1) Yes, I think your understanding is correct (I say I think because I think I understand what you're saying ;-) ). The flag you are using means "start this service automatically if somebody tries to bind to it and keep it running as long as somebody is bound to it, but once nobody is bound to it, feel free to kill it".
2) Check out the START_STICKY flag as described here. That should allow you to start the service and keep it running regardless of what happens to the calling Context
In general, onDestroy() means your activity is about to be killed. When you rotate the display, the Activity is killed and recreated. You are responsible for saving any state to the Bundle in the appropriate method and then restoring it in onCreate().
Does your service get killed:
if there is a second Activity on the stack?
if you handle configuration changes?
Why do you need your service to stay alive after your application has been destroyed?
I think the general rule of thumb is that you can't be sure when your activities and services will be killed. If this is blocking something you're trying to achieve, there may be a clever way around it.
Edit - you can actually handle the orientation configuration change so that your activity isn't restarted. For more info see the second half of this answer.
About the "second" Activity: Image you start activity A and then activity B. Now you rotate the screen while B is showing, causing B to restart. Will A be restarted at this point? I'm not sure, but I have a hunch that A will tend to stay alive and keep your application alive during the orientation change. This might be another strategy for keeping your service alive if that's what you're aiming for.
a service is destroyed only when both of the following are true:
All calls to bindService() have been matched by corresponding calls to unbindService().
If somebody called startService(), somebody also called stopService() or the service called stopSelf().
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.
this gives a great solution which is also fairly correct and safe!
say there are 2 activities ('viewer' and 'chat' in this example) that need a service, if both bindService AND startService. Also using the binder they update 'viewer_connected' and 'chat_connected' during onStart and onStop.
Then the service runs a loop in a thread that does this:
public isRunning = true;
while (isRunning) {
if (viewer_connected) {
// send update to viewer activity
}
if (chat_connected) {
// send update to chat activity
}
try {
Thread.sleep(5000);
} catch (Exception e) { isRunning=false; }
// 3 second timeout before destroying service
if (!viewer_connected && !chat_connected) {
try { Thread.sleep(3000); } catch (Exception e) { isRunning=false; }
if (!viewer_connected && !chat_connected) isRunning=false;
}
}
stopSelf();
This works because it needs both the activities to unbind AND the service to stopself() before it destroys the service, meaning there is a timeout before the service gets destroyed.

Categories

Resources