Android: service destroyed when display is rotated - android

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.

Related

Delay between bindService() and onBind() when starting a Service

I'm facing a strange problem with my app. I have a LocationService that runs in the background. The way I manage its lifecycle is:
In onResume, every activity uses bindService(intent,serviceConnection, BIND_AUTO_CREATE) like that the service is automatically created when needed.
In onStop, every activity uses unbindService(serviceConnection)
This works because when switching activities, the new Activity onResume is called before the old Activity onStop method
The problem I have is, lets say I start from the home screen and I launch the app with an Activity that has a fragment in it. The order of the function call is as follows
Activity onCreate --> setContentView is called here
Activity onResume --> here bindService is called and should create the Service
Fragment onResume
Service onBind method is called
My question is why is there a something else between my bindServiceand onBind calls?? I have a feeling this has something to do with threading issues.
Well, this isn't a very good answer, but why wouldn't there be something else between your bindService() and onBind() calls? You seem to be assuming that when you call bind the system will immediately create and start your service, and no such guarantee is provided.
You haven't indicated whether yours is an IntentService, or just a regular Service, and this might affect the speed with which your service is launched, but my answer would be the same.
Also, I'm assuming that your ServiceConnection object is called, as expected, sometime after your service's onBind() returns.
I say this not based on having read anything definitive, but because I had a similar experience: I was surprised and annoyed at how long it took before my service was created and my ServiceConnection was called, even though I returned from the service's onBind very quickly. (My fragments needed data from the service to create the initial UI so any delay in the creation of the service meant a delay in displaying the initial UI to the user.)
In the end I settled upon launching my service using an Intent rather then a bind, e.g.
Intent si = new Intent( this, com.company.MyService.class );
si.setAction( MyService.SVC_BIND );
startService( si );
I then sent MyService.SVC_UNBIND in place of calling unbind. When I received the UNBIND intent in my service I cleanup and then call stopSelf(). These are user actions - I just named them for how I'm using them.
I believe this was faster, but looking back upon my comments from that code I don't have any specifics. Note that this meant no ServiceConnection, but I'm making some direct calls from the activities into the service, and using LocalBroadcastManager a fair bit.
Another option to consider (in order that your service be started more quickly, if that is your goal here??) is to launch it in Appliction.onCreate(), rather then waiting for Activity.onResume(). All of these options make it necessary to do some extra work to determine when to stop the service, compared to your current, normal, scheme where that is taken care of for you.
In my case, my issue was using android:process attribute for <service> element within Android Manifest, which is supposed to improve performance, but in reallity, maybe it does once the service is running, but it takes a very long while to reach onCreate() (and so also to reach onBind()). For me it was taking minutes. Now Apps and services run smooth and as expected.
More info:
https://developer.android.com/guide/topics/manifest/service-element

Should I start/stop service in onStart/onStop, or onCreate/onDestroy

Currently, I have service, which runs in separate process. Here is the code in main activity.
#Override
public void onStart() {
super.onStart();
// Start auto complete service.
autoCompleteServiceIntent = new Intent(AutoCompleteService.class.getName());
startService(autoCompleteServiceIntent);
bindService(autoCompleteServiceIntent, serviceConnection, 0);
}
#Override
public void onStop() {
super.onStop();
// Stop auto complete service.
unbindService(serviceConnection);
stopService(autoCompleteServiceIntent);
autoCompleteServiceIntent = null;
}
The service will have the following characteristics.
The service runs in separate process. The reason is that, it will load a large data into memory. Having the service to run in separate process, will allow us to have larger memory limit.
Once main activity dead, the service shall dead too.
I was wondering, should I start/stop service in onStart/onStop pairs? Or, shall I start/stop service in onCreate/onDestroy.
The good thing I can think of, when having the code in onStart/onStop pairs is that, I can release unused memory immediately, whenever the activity is invisible. Hence, free up large system resource. Note, onDestroy is not always being called immediately, even the activity has quit.
The bad thing is, if I press HOME and come back frequently, my service will perform memory loading/unloading frequently. This may cause my application performs considerable slower.
In your scenario you should stop the service onDestroy the reason been is that, its called when the activity is destroyed self, foreclosed or by system when it needs memory. So that will be a appropriate place to end the service.
Where else onStop will be even called when you move back and forth in your application or visit home. The reason onDestroy is not called on home press is the activity is not destroyed yet. Where as if you close activity pressing back it will call onDestroy.

Use of onDestroy( ) in Android

If Java provides Garbage Collection, then what is the need of onDestroy() in Activity Lifecycle?
onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space.
Here is an example......
public void onDestroy() {
super.onDestroy();
}
OS decides when things "go away." The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed but it does not mean that the activity will, in fact, be GCed. Here is a good article that I recommend people to read that relates to creating an exit button. While it's not exactly what you asked about, the concepts will help you understand what's going on.
You can use onDestroy() to finalise the program. I have used it in the code bellow to tell the server that the client is closing its socket to the server so I can notify the user on the server end that the client has disconnected.
client:
...
protected void onDestroy(){
super.onDestroy();
if(connected) {
clientMessage.println("exit");
clientMessage.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
}
...
server:
...
while (connected) {
input = clientMessage.readLine();
if ("exit".equals(input)){
break;
}
...
}
...
onDestroy() is a method called by the framework when your activity is closing down. It is called to allow your activity to do any shut-down operations it may wish to do. The method doesn't really have anything to do with garbage collection (although your shut-down operations—if any—might involve releasing additional resources that can be gc'ed). In particular, it has nothing to do with C++ destuctors (despite its name).
If you have no shut-down operations to do, you don't need to override it. The base class does essentially nothing.
onDestroy may be called when an activity is destroyed, but you can not count on it. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
See: http://developer.android.com/reference/android/app/Activity.html#onDestroy()
In the Android Activity Lifecycle's onDestroy docs:
onDestroy() is called before the activity is destroyed. The system
invokes this callback either because:
the activity is finishing (due to the user completely dismissing the activity or due to finish() being called on the activity), or the
system is temporarily destroying the activity due to a configuration change (such as device rotation or multi-window mode)
The Activity#onDestroy() API docs also answers it quite well:
This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. source
As the quote from the docs say, its for preventing a destroyed activity leaving things around (e.g. memory leaks through referencing, threads), but only when the rest of the app still runs. If the application process ends, it doesn't matter if you forget to clean up threads or other resources since the OS will do it for you. You don't need to override onDestroy.
There is no need to do what sam786 is doing (overriding and just calling the super method) as that is absolutely useless. All other answers seem to go along the lines of "clean up", but don't explain what kind of clean-up or when. You should not be saving any data in onDestroy(), as you can't guarantee it will be called, so you will lose data sometimes. It won't be called when you press the home button, for example (the case where you want data to be saved).
The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed
Article Exit Button in Android
It gives your program a chance to do things like cleanup resources (say threads) so that they don't pollute the associated application. If you don't have any use for it, then don't override it.
See:onDestroy()-Android Reference

Android: How to backup a database when the application gets closed?

I am needing help to determine the right approach. I want to make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed. I want to call this method from a central class called Main which extends Application. The reason for that is, that I need to use several activites and I want to call the backup Method only when needed (like described when the whole application gets destroyed or interrupted by another application). I try to avoid calling this backup method in every activity in their onPause() methods.
I thought about starting a service in the onCreate() method of the application, and starting the backup method when the service gets destroyed. But this won't help in the case of an interrupt, as far as I understood the logic behind services. And also the service doesn't seem to start. startService(new Intent(getApplicationContext(), BackupService.class)); Furthermore I don't think it is a good approach to just use the onDestroy() method of a service, this is not what the service class is made for in my opinion.
So summarizing my Question, do you know a better way then using a service, or if not do you know how I should use the service to be able to call a backup only at the point when the whole app (and not only an activity) is interrupted or destroyed.
First of all, if your service "doesn't seem to start", you are probably doing something wrong.
To accomplish your goal make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed:
There are three cases in general here.
If you want to do it in the activity layer:
To know when your application is crashed, you need to implement a custom handler to catch the uncaught exceptions.
To know when your activity is "interrupted", the only way is do it in onPause.
To know when your activity is "terminated", the only way is to do it in onDestroy.
This will require you to have a clear navigation and only do it in your "main activity", and all the other activity starts and comes back to it OR use a flag to indicate if the pause was caused by going to another activity.
If you want to do it in the service layer: (Your way of doing it onDestroy won't allow you to detect interrupted case since you will have to start service sticky to keep it running)
You will have to set up a flag on each activity onBind (you will have to bind it and unbind it) to know if it is a crash/interrupt/termination, which will complicate other part of your code.
To avoid running repetitive code, you will have to create a generic base class and extend your other activities from it.
I use this approach to play background music in one of my games, but I guess it works in this scenario as well.
Use a boolean flag to indicate whether or not your app is launching another part of your app.
boolean movingInApp = false;
....
movingInApp = true;
Intent intent...
.....
public void onPause() {
if(!movingInApp) {
//start service
}
}
public void onResume() {
movingInApp = false;
//Stop service
}
By setting the value of movingInApp to true before launching any intent etc, you can prevent your app from starting the service. Remember to set it to false again later in your onResume() method. If the system makes your app go to the background, this will be false, and your service will be started.
Why dont u have all of your activities extend a base activity which in turn extend the android activity class
I the base activity have backupDB method in the onPause
Therefore u dont have to put it in every activity pause method

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.

Categories

Resources