Can I safely stop a Service in my main Activity's onDestroy method? I know that onDestroy is not guaranteed to be called, but I also do want to keep my Service running until the app is destroyed.
I'm thinking that maybe in all situations where the activity is destroyed, the service would also be destroyed?
You can stop a service in the onDestroy of an activity, but to do it successfully requires either:
Running a Service in the Foreground
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory. A foreground service must provide a
notification for the status bar, which is placed under the "Ongoing"
heading, which means that the notification cannot be dismissed unless
the service is either stopped or removed from the foreground.
For example, a music player that plays music from a service should be
set to run in the foreground, because the user is explicitly aware of
its operation. The notification in the status bar might indicate the
current song and allow the user to launch an activity to interact with
the music player.
or Managing Bound Services
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely
In all your activities, manage any resources you have created within that activity and with a null check, close them down. Like you have in your service class. If you want to override the parent onDestroy, place your custom code before super.onDestroy.
There's more detail about this here.
but I also do want to keep my Service running until the app is destroyed.
The activity can remain on the stack in the stopped state and will not be destroyed until more memory is needed. This means that there is no fixed time that the service will continue to run until the activity is destroyed.
Activity Lifecycle
If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.
The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().
To ensure that all your resources are cleaned up, you could either call finish() on the activity, or end the service in the onStop() method or use a timer in the onStop(), that will end the service or destroy the activity after x time.
The problem with calling finish() is that if the use navigates back to the activity quickly, it needs to be recreated. The problem with using stop() is if the activity is restarted the service will need to be restarted. So a timer could be a way to keep the activities natural state preserved to allow user navigation, but it would need to be stopped if the activity resumes in onResume().
For protected void onDestroy ()
Perform any final cleanup before an 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. You can distinguish between these two scenarios with the isFinishing() method.
Yes it is safe to do it in onDestroy. Because before killing your activity background service or forground service that is bound to component will get killed by system as priority for service running in background is lesser then component you are interacting with.
Related
My activity binds to a service in onResume and unbinds from in onPause so it can use the service as long as it is active.
Now I want to avoid this (un)binding if the activity is recreated only because of an orientation change (display rotation). Keeping the connection object alive (instead of creating a new one) is possible using onRetainCustomNonConfigurationInstance().
But I don't see a way to know when I can skip unbinding in onPause and later re-binding in onResume. What can I do to handle this special case?
Another thing I'm thinking about is, is there a way to get told when the app goes active or inactive? Then I could keep the service alive for all my activities and unbind from the service only if the app gets destroyed or put in the background. (compared to bind to the service for each activity, which I have to do to in order to unbind the service correctly when an activity is left and no other one is coming)
i have a service that returns START_STICKY onStartCommand, and is started by startService on the Application's onCreate, in my activities i bind to this service interchangeably, but for some reason the Service gets destroyed everytime all my activities unbind to it, but i can gaurantee stopSelf\stopService was never called. what could be the reason?
The Application.onCreate() only gets called if the application was never run or had been destroyed to free memory. If you need a long lasting Service that continues to run in the background after your Activity has ended, then you can look into running it as a foreground service, which will make Dalvik try not to kill it unless it absolutely has to.
Ok, found the answer - DONT relay on a call to startService on Application's onCreate, because in my case i called stopService only when my main activity was exitted by user back press, but even though there were no activities nor services running for my application android did not kill the process and did not release the Application object for garbage collecting, this caused that the next time user launched my app, Application's onCreate was NOT getting called as it already existed, therefore the service's lifetime was handled only by the activites binded to it and this is why it got destroyed when all activites unbounded.
ehhhh Android and their weird design...
Android provides the Service class, which can be useful for background or non-UI operations.
I have a question about Services' lifecycle.
I know that bound services have the lifecycle like following:
Some component starts the Service via bindService() -> onCreate()
onBind()
process
The binding component calls unbindService() -> onUnbind()
onDestroy()
My question is:
Activities usually call unbindService() at onStop().
However, the Activity can be killed without calling onStop() - I mean, when the system memory is low, the only method that must be called is onPause(). onStop() is after onPause(). Before calling onStop(), the Activity can be destroyed.
In this case, the Service didn't get unbindService(), so the Service is still running. Is this right?
Of course, this rarely happens because Services are background by default. (Services are more likely to be killed by system on low memory.) However, a "Foreground" Service has higher priority than the "onPause()ed activity." according to http://developer.android.com/guide/components/processes-and-threads.html . In this case, the binding activity will be killed first.
If this thing happens, the Service does not end? If memory is not low anymore, then the Activity will be created again, but will call bindService() again since it is a new instance. Also, the Activity even may not restart. Isn't this right? What can I do in this case?
The Service is killed, but if you have 'return START_STICKY' being returned from the onStartCommand(...) [AND you are starting the service using 'startService(intent)'], the service will start back up again. The Service will start back up even if the Activity is not opened again.
I have run this example - the BoundedAudioService example and tested by killing the activity - the service restarts itself. (By restart I mean, the onStartCommand(...) of the service is called again)
A bound service typically lives only while it serves another application component and does not run in the background indefinitely.
I want to know what is the best place in an Activity to bind to a service?
I saw examples doing it in onResume() and also in onCreate(). I was asking myself if it is not a problem putting it into onCreate(), because in onPause() I will do a unbind to the service, so I don't get a serviceConnectionLeak, if I leave the activity. Now if I press the Home Button and then switch to the Home Screen, the Activity will unbind from the service, when I go back to the Activity from the Task Manager, then onCreate() will not be called and if the code is trying to access a function from the service I will get a NullPointerException. If I bind and unbind only in onResume() and onPause() I don't have this problem. Am i right?
I would generally recommend doing this in either onCreate()/onDestroy() or onStart()/onStop(), depending on the semantics that you want:
If your Activity wants to be interacting with the Service the entire time it is running (for example maybe it can retrieve some data from a network for you and will return the data when ready and you want to allow this to happen while in the background so if the user returns you will have the data ready), then onCreate()/onDestroy() is probably appropriate. Note that the semantics here is that the entire time your Activity is running it needs the Service, so if this Service is running in another process then you have increased the weight of it and made it more likely for it to be killed while in the background.
If your Activity is only interested in working with the Service while visible, then onStart()/onStop() is appropriate. This means your Activity will unbind from the Service when the user leaves it (and it is no longer visible) and connect back up the next time the return and it is re-started and resumed.
I generally wouldn't recommend doing bind/unbind in onResume() and onPause(). These generally won't decrease significantly the amount you use the Service (and thus your overhead), and in fact, because a pause and resume happens at every activity transition, this is a code path you want to keep as lightweight as possible. Doing it here can have other unexpected negative consequences: for example if multiple Activitys in your app bind to the same Service, when there is a transition between two of those activities the Service may also get destroyed and recreated as the current Activity is paused before the next one is resumed.
Also these pairs (onCreate()/onDestroy(), onStart()/onStop(), onPause()/onResume()) are intended to be the proper pairs for acquiring and then releasing resources (such as binding to Services, registering receivers, etc) to ensure that they are correctly acquired prior to being needed and released (and not leaked) when no longer needed.
What you say is correct. In most cases you will want to register in onResume() and unregister in onPause(). If you use onCreate() and on onDestroy() you will still be registering for updates when you are paused, which is being a bad citizen. If you register in onCreate() and unregister in onPause(), when you resume the task the registration will be gone, which is almost certainly not what you want.
Is there a way I can test if there are any other activities in my app still alive? I am looking to stop a service in an onDestroy method, but only want to do this if there are no other activities from my app still alive on the stack.
I have the call stop the service in the main activity's onDestroy() method. This works perfect EXCEPT that if a user launches my app, then launches a few activities in my app, then hits the home screen and RELAUNCHES my app, they will subvert my order and the main activity will now be above other activities of my app. From this state, if they hit the back button and 'back out' of my home screen they will trigger the onDestroy() method and kill the service even though there are other activities open on the stack. I want to avoid this by stopping the service ONLY if I am sure there are no other activities of mine open on the stack. Possible?
How can I launch a service that will
continue to run as long as any of my
app's activities are still on the
stack, yet be stopped when none
remain?
Don't use startService() and stopService(). Instead, use bindService() and unbindService(), even if you don't really need the bound connection. The bind/unbind is reference counted. If you call bindService() with the BIND_AUTO_CREATE flag, the first bindService() call will start your service. Then, when all bindService() calls have had matching unbindService() calls, Android will automatically shut down your service.