Why unbind Service onDestroy? - android

I've seen it mentioned in multiple sources, that if an Activity binds a Service, it should unbind it onDestroy. Why? Since the Activity is destroyed, it seems like the service will be unbound anyway. If it was "started" - it doesn't matter anyway. And if it was auto-started by the activity - it will close anyway if no others bound it.
So why unbind it?

Activities need to handle configuration changes, such as when the screen is rotated, or the user changes locales, or the device enters night mode.
The default behavior of the foreground activity, when a configuration change occurs, is for it to be destroyed and recreated.
As a result, calling bindService() on an Activity is not a good idea. We want the binding to remain intact across the configuration change. Otherwise, our service will get destroyed and recreated, along with the activity (assuming that the activity has the one-and-only binding and nothing else started the service).
So, the recommended pattern is to call bindService() on the Application singleton. Then, you can pass your ServiceConnection from the old activity instance to the new activity instance. Retained fragments work great for this, as you can then call unbindService() in onDestroy() of the fragment, so that when the activity is "permanently" destroyed (e.g., user presses BACK, you call finish()), your binding can be released.
With all that as background, on to your specific concern.
First, you assume that a destroyed activity automatically unbinds from any services that it bound to via bindService() called on that Activity. It's possible that this happens, though I do not recall that being documented behavior, and it's the sort of thing that developers should not rely upon.
More importantly, in most cases, calling bindService() on the Activity is not the right approach. Otherwise, you get into the problems that I outlined above.
But, following the call-bindService()-on-the-Application pattern, I would not expect there ever to be some sort of automatic unbinding, because the Application singleton is never destroyed. So, if you fail to call unbindService() somewhere (e.g., in onDestroy() of the retained fragment), you will leak your service.

Related

Stop Service in Activity onDestroy

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.

Singletons in Android activity and service lifecycles

I am trying to use a static singleton DataManager that makes network requests and holds arrays of data for my Activity, instantiated in my Activity's onCreate() class, but the idea that the Activity gets destroyed every time there is an orientation change is tripping me up. I don't want to re-create a new singleton and re-populate it with data every time the user changes the orientation or comes back to the screen.
Even if I make DataManager a Service, if I make it a Bound Service, it seems like the Service will get destroyed whenever my Activity gets destroyed, but if I don't make it a bound service and use startService() and stopService() in my Activity, it also gets destroyed whenever my Activity is destroyed.
Also, if I use onSaveInstanceState() and onRestoreInstanceState() to save my instance of the singleton, it possible that my singleton would get destroyed when my Activity is inactive, since there is no longer a pointer to it. Then Activity B using the same DataManager class could create another DataManager instance while Activity A is inactive. Then Activity A wakes up, inflating another Data Manager, giving us 2 DataManagers that are no longer singletons and may have inconsistent data.
I have read elsewhere that I should not subclass Application to maintain app state, but I don't understand how it would work any other way. Thanks for any clarification.
Subclass the application class and then instantiation your singleton within the application.onCreate() callback. This way it will be available for the lifetime of your application rather than the lifetime of a single activity. Careful that this won't be garbage collected until someone kills your app so don't have too many "Global" singletons.
DO NOT do the work in Application.onCreate(). You will be slowing down your application start up, no matter what happens. This is not advised for Android applications, you want your app to start promptly.
Instead, if you really need a singleton, have it construct lazily when it's necessary.(If you are sure you will use it, you you can also force the construction asynchronously from a separate thread when your activity starts). When your activity gets destroyed, it doesn't mean the whole process will be immediately torn down, so your singleton will stay alive.
Also, if you are using a singleton, make sure to be able to clear it when memory is low. You will need to implement Application.onTrimMemory(int) and clear the singleton from there.

Who is the "client" of a Service - a Context, or a ServiceConnection?

I have found and read various posts here on SO that mention you should use getApplicationContext() when binding to a Service - instead of this (in an Activity) or getActivity() (in a Fragment).
However, this raised the following question for me: The documentation repeatedly talks about the "clients" of a Service, e.g.: "When a service is unbound from all clients, the Android system destroys it" (http://developer.android.com/guide/components/bound-services.html).
What is meant by client in this context:
the Context that was used to call bindService()
or the ServiceConnection that was supplied to bindService()
Let's suppose I have two Fragments that bind to the same Service - using the Application Context and each with its own ServiceConnection.
When will the Service be destroyed?
If my second interpretation is true the Service would be destroyed when all connections are closed, i.e. when each Fragment has called getActivity().getApplicationContext().unbindService(mConnection). If the first one is true it should be closed as soon as the first Fragment makes that call because that would "unbind the Application Context"...
So, which interpretation is true? (I hope it's the second one...)
You use getApplicationContext() so that the ServiceConnection survives e.g. Activity orientation changes (the activity gets destroyed and recreated and so does it's context). According to documentation the service might disconnect when the activity is stopped (not destroyed).
The 'client' is anyone who holds an active ServiceConnection. When nobody is connected to the service it is no longer needed and therefore destroyed (unless also started by startService(...)). The ServiceConnections are counted not the contexts.
I haven't tested whether the connection closes automatically if said Fragment is destroyed. My guess is NO, because the application context survives - you have to unbind explicitly in onDestroy.

details of Android application components destruction and recreation

Could someone push me in the direction of some concrete, trustworthy (and preferably concise) information on the following:
The order in which components are destroyed and (where applicable)recreated by the system
(Fragment, Activity, Activity's Threads/AsyncTasks/Timers,
static data(when are classes unloaded?), Threads/AsyncTasks/Timers in other classes, host
TabActivity, ActivityGroup, bound local Services, Application, process)
both when the app is in the background, and in the foreground.
At which points the destruction can stop (what states can be encountered
upon return to the app - like "everything including the Application object
destroyed, process alive"?
Is it possible (without modifying Android) to programmatically cause the same kind of destruction
ourselves, so that it is indistinguishable from when the system does it, or is a separate mechanism needed for when we ourselves choose to free memory (triggered by onLowMemory)?
Reliable reproduction steps of all scenarios from 1) (would junit.framework do? I haven't investigated that) ?
"If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, only the root activity is restored": is this aside from the process/component lifecycle/destruction, or tied to it?
I have read various sources give pieces of information, often incomplete and misleading, sometimes incorrect.
I admit, I have skimmed over some parts of the documentation, so i may have missed or misunderstood something.
[EDIT] To avoid misunderstandings: What I am asking about is Android destroying components to free memory, bypassing Activity.onDestroy.
When I put the app in the background and return later, the one of these sequences will occur:
onPause, onStop, onRestart, onStart, onResume
onPause, onStop, Application.onCreate, onCreate(notNull), onStart, onResume
[EDIT2]
Bounty started. Need reliable info on: Activities, Fragments, Application, bound (potentially remote)Services, process.
Partial/full destruction scenarios. See 1st point.
This is what my experience, and that of devs I've asked, seems to suggest:
Fragments are not autodestroyed.
non-visible Activities on the app's stack can be autodestroyed in any order, and in any number.
destroyed Activity's (or any other class's) Threads and statics remain untouched until Application is destroyed.
TimerTasks: haven't tested.
bound local Services: destroyed somewhere between the destruction of the last binding Activity and of Application.
Application is the last thing to go within a process, and "goes" along with all Threads.
the process can exist for a long (20+ minutes) time after the destruction of the Application object, unless you have an automatic task killer.
Activities under TabActivity or in ActivityGroups are not autodestroyed, but go all at once if the container is destroyed.
Example: a TabActivity with ActivityGroups under tabs. All Activities live. Another Activity is started, fullscreen. The TabActivity with everything in it is now eligible for destruction by Android, all at once or not at all.
NO.
If you destroy an Activity manually, it goes through the entire lifecycle and doesn't pass a Bundle to onCreate when started again.
Also, onLowmemory is unreliable - even with small allocation steps, it might never be called before OutOfMemoryError is thrown.
NO.
Despite the autodestruction/restoration being such a major feature in Android, there isn't any way to test such scenarios.
This is probably related only to whether the process still exists or not. If it does, Android will attempt to restore the old Activities. If not, it's a clean restart.
The above include some assumptions.
I am still waiting for someone to confirm it and supply some docs (guarantees not dependent on the current implementation of classes).
Please, PLEASE correct me if any of this is wrong.
Edit: The above information may be out of date, it was tested on Android 2.1-2.3
Credit for this goes to hackbod for writing it here(read the whole answer), and to CommonsWare for linking in a comment.
In short: All the docs, rewritten many times, continue to lie to us. They're not misleading, they just give us untrue information. Unless you're using Fragments (dunno if support v4 counts, too), Android frees memory by killing the whole process, or does nothing.
Of course, this does not address everything:
Point 4 of the question
Why I frequently saw onCreate(notNull) on pressing Back on an Activity stack with Activities handling all config changes (Android 2.3.7)
How this relates to the widely accepted belief that onPause is the last call you are certain to get, and onStop may never get called (how, then, can the app go to the background, to be killed?)
We're getting somewhere, though.
Well, my friend,
I guess you'll have a lot of trouble in your research. Basically because you're talking about two black boxes: the Dalvik garbage collector and the android heap manager. I would say that you cannot trust that android will follow any order of object destruction. But, you can trust that this lifecycle is going to be followed [Programming Android, 2011]:
Activity Lifecycle:
onCreate() - Called after the instance of the activity has been created for the first time
onRestart() - Called after an activity has been interrupted, just before the onStart();
onStart() - Called when the object activity and their visions become visible to the user;
onResume()- Called when the object activity and their visions become interactive to the user;
onPause() - Called when a different instance of the activity is going to get visible and the present activity ceases to interact with the user
onStop() - Called when the activity is no longer visible or is not interacting
onDestroy() - Called when an activity instance must be destroyed and it's no longer needed.
Fragments have different lifecycles including methods onAttach, onCreateView and onActivityCreated .
But, why do you care about the objects order of destruction? I can't see no reason for you to monitor such events, but if you really need, learn more about the garbage collector.
The ActivityManagerService#trimApplications()method remove any unused application processes if the application's current receiver is null, does not have any activity and service.
When it comes to activities, they will be only destroyed on on Destroy() until and unless developer manually calls the finish() function,
Fragment life cycle is a completely matched to its parent activity, so when parent activity destroys on on Destroy(), the fragments on Destroy() as well will be called.
Timer Tasks will finish their work and become candidates for garbage collection, once the activity creates them the task runs in its own thread, no relation with activity, even if the activity is destroyed, the task finishes itself....
This is not a complete answer but what I would recommend is that you place toast messages in each of these methods. Add in your own onPause(), onStop(), onResume(), etc. and inside put a line like this:
Toast.makeText(this, "onPause()", Toast.LENGTH_SHORT).show();
You cannot directly call these methods, however moving another activity to the top of the stack will of cause these methods on the existing activity to be called. One more thing to keep in mind is that onCreate() need not be called every time you start an activity. It really depends on how you start the activity, for example if you send this intent
Intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP);
it will appear call onNewIntent() instead if it has already been created. In summary the best thing is just to watch the Toast messages. Also you really need to focus on using the debugger. Place a breakpoint on each method and you can see it. One thing I am sure of is that you cannot directly invoke these methods like onPause(). Also keep in mind that in general you don't know when onDestroy() will be called.

Binding to Service in onCreate() or in onResume()

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.

Categories

Resources