onStop() and onDestroy() might not be called. What good are they? - android

This has always confused me about the Android lifecycle. In the documentation on Activities, Table 1 and the text below it indicates that onstop() and onDestroy() might never be called. onPause() is the last lifecycle method that is guaranteed to be called.
If onStop()/onDestroy() might not be called, what good are these methods? I recognize where they fall in the lifecycle--I'm not asking about what they signal, I'm wondering what kind of code belongs in them if you can't count on them being called. Other posts asking about the utility of these methods say you should use them to free up resources--would this not be unreliable and bug-prone, as those methods may never be called?
I could imagine something like if the app is killed and those methods aren't called, the process itself is killed so any resource pointers you have might be garbage collected or otherwise cleaned up for you. In that case, onStop()/onDestroy() might be responsible for cleaning up resources that would be held onto until the process is killed. That seems a bit convoluted, however.
Does anyone have any examples of how onStop()/onDestroy() can be used correctly and safely, without introducing subtle bugs or resource leaks depending on how Android decides to shut down the Activity?

I could imagine something like if the app is killed and those methods aren't called, the process itself is killed so any resource pointers you have might be garbage collected or otherwise cleaned up for you. In that case, onStop()/onDestroy() might be responsible for cleaning up resources that would be held onto until the process is killed. That seems a bit convoluted, however.
This is basically correct for onDestroy(). The point is that you should free up resources that it would be wasteful to keep if your process is going to survive, but without that Activity continuing to be needed. Think of this as the case where only the individual Activity is being destroyed.
In contrast, if the process hosting your Activity is being killed, it is the operating system which will do the cleanup of resources held by the process. Think of this as the case where everything is being destroyed (though that is not strictly accurate, as you can have multiple processes).
There have historically been some issues with things like in-use status of the camera that did not get properly cleaned up by the operating system, but the current status of that would be a distinct issue.
The purpose of onStop() however is somewhat different - while it can happen on the way to death, this does not itself indicate the death of an Activity, but rather only that the Activity is ceasing to be visible on screen. Hence this could be a time to stop visual updates and potentially release resources involved with that, as well as other behavior that you want to have linked to on-screen status.

Related

onCreate() and onDestroy() NOT symmetric?

I am learning android and came up with what I think as a weird observation:
based on the diagram and description on https://developer.android.com/guide/components/activities/activity-lifecycle
It seems the two callbacks onCreate and onDestroy are not symmetric.
It seems that when an app loses its focus or be put to the background, the system could kill the app without calling onDestroy. Later on, when the app is up again, onCreate is called.
I tried to test this, but couldn't figure out how to simulate the situation when the system would kill the app because of memory issues. I tried to open a lot of apps on my phone, the test app was never killed :)
Let's say it does happen in some cases. Does that mean you could have onCreate be called more than onDestroy, which could potentially cause memory leaks if you happen to acquire resources in onCreate and release the onDestroy? If my observation is true, any best practices out there to solve the resource release issues?
Thank you.
The documentation can really explain this better.
However, in short, onDestroy() will be called if an Activity is ended with finish() or Android needs the resources that your app is using.
I will typically not use onDestroy() to manage resources. In fact, I do not think I have ever used onDestroy() in any app I have written.
I will use onPause() to ensure that resources are gone in a timely fashion. You will only really need to do that for resources that are registered (like BroadcastReceiver). Stopping repeating Handler messages. Things like that.
i'm not sure but i think there is a way to simulate system kill app with adb command
https://possiblemobile.com/2017/10/android-testing-app-killed-background/
I tried to test this, but couldn't figure out how to simulate the situation when the system would kill the app because of memory issues.
Just use Settings->Developer options->Dont't keep activities mode to get onDestroy all the time. Also use Background process limit at the same menu.
Loose call of onDestroy is extreme situation. System calls onDestroy every time activity destroyed, even in not enough memory case.
Thanks everyone. With tips from #Igor, I was able to test and prove the points mentioned by #Knossos: OnDestroy is called as soon as the app loses the focus. Which means onCreate and onDestroy are still symmetric, as far as I am aware. Which also means the diagram on the android documentation site (https://developer.android.com/guide/components/activities/activity-lifecycle) needs a little improvement.
Thanks again for everyone's input. As to the best practices for resource management, now that I think more of it, it deserves a whole lot of in-depth discussions, as many factors could contribute to the complexity: the types of resources, the system overhead of getting and releasing them, etc...

How to manage stopping a Service with a long-running onDestroy?

I have an android Service class which has a long running onDestroy. I need to prevent this as it can cause a hang when there are activities running.
It seems some people are happy starting a thread/AsyncTask in the onDestroy method to hold the long running code, though I'm concerned that the threads may be killed. Another solution may be to use startService instead of stopService with an intent that tells the service to start a shutdown thread which calls stopSelf at the end.
Are any of these solutions sensible, or is there another way?
A shutdown Intent is a reasonable way to go here.
Starting another Thread in onDestroy is a bad idea though. It might be called or not called when you don't expect or want it.
Edit: To persist important information neither of these ways is a good idea.
You cannot assure that these methods actually get run before your process is killed. For non-important data you could of course go these ways, but you'd better persist your data as soon as you get it, or at least within a fixed interval (if you have a continous data input).
From the official Documentation:
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here.
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. 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.
And here the Documentation specifcally for services:
Called by the system to notify a Service that it is no longer used and is being removed. The service should clean up any resources it holds (threads, registered receivers, etc) at this point. Upon return, there will be no more calls in to this Service object and it is effectively dead.
(I've included the Activities documentation, because it is more precise)
You should be aware that there is no absolute guarantee for onDestroy to be executed.
It seems some people are happy starting a thread/AsyncTask in the onDestroy method to hold the long running code, though I'm concerned that the threads may be killed.
I would assume that you're trying to either free some resources or send some sort of message to server.
In case of resources there is no need worry - if you'll start new thread it will be killed only together with hosting process (your app). If that would happen - it's ok, system will release resources for you.
In case of server message - that is a bit more complicated. I like your idea with sending command to a Service instead of calling stopService. Other option would be to start another tear-down Service from your onDestroy which will perform long running operation and shut down itself.

How can we guarantee that onPause will be called?

Going of this question
android save game state in onPause or onDestroy?
The answer highlighted that the person asking the question should save game state in onPause because the onDestroy documentation says "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." In these situations, how can we ensure onPause will be called? Is it possible to control what methods are called in these situations? Seems unpredictable
onPause will be called every time your activity leaves the screen, before it is finished or if something overlays your activity that keeps the user from interacting with your activity.
You don't need to worry that onPause is not called.
For more information look into the starting and stopping activity training or the Lifecycle Api Docs
You should save temporary instance state in onSaveInstanceState(). This method recieves a Bundle parameter which you can use to write state to. The Bundle is then sent to onCreate() when your app is restarted.
If you need to save instance state more permanently, then save it to a database or SharedPreferences. According to http://developer.android.com/training/basics/activity-lifecycle/stopping.html, you should use onStop() for more CPU-intensive operations rather than onPause(). I don't think you need to worry about onPause() being called in normal use cases. As far as I can tell, it is guaranteed. (Of course, there are always catastrophic failures, such as the user pulling out the battery of the device, but there's not much you can do about that.)
It's almost certain that onPause() will always be called. The reasoning is that it's highly unlikely the "system" will aggressively kill an active (i.e., visible) Activity.
In order to free resources, the Android OS effectively reserves the right to kill dormant processes - in particular ones that have been long-running but not recently used. In order for your Activity (and its process) to qualify for this, at some point you must have sent the Activity to a background state, e.g., pressed HOME or started another app's Activity. The simple fact your Activity is no longer visible means it will have been paused and onPause() will have been called. It's almost certain that the Activity will have been stopped and onStop() will have also been called.
What you have to remember is Android has been around for a while now and early devices had RAM measured in 100s of MB and the system behaviour possibilities and documentation reflects this. More recent devices have RAM measured in GB (even 10s of GB) so unless a user really pushes their device to the limitations of its resources, aggressive clean-up of app processes becomes less likely.
You can show Dialog for User to Act Accordingly.When Dialog will be opened to ask user that he wants to quit or not,Activity will definitely call onPause() and at this time you can write your game state saving code. Its better to write code on onPause() because at onDestroy() resources are freed by os.

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.

Application Process still around after app is closed

I have an application that I suspect might be leaking a thread or its context. What makes me think so is that after closing the app, the process is still running (visible process monitoring applications). I've cut everything in the code, going as far as calling finish() from the onCreate. The process is still around and annoying me.
I've read that (from here)
An empty process is one that doesn't hold any active application components. The only reason to keep such a process around is as a cache to improve startup time the next time a component needs to run in it. The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.
How do I know if my process is still around because of circular reference or context leak or anything else equally bad or if is simply that the process is empty?
The fact that you still see the process will not give you any information about the existence or not of references to objects in your application. There's no magic that's going to answer that for you.
If you are worried, you should inspect where (if anywhere) you are registering callbacks (AKA listeners) with system services. This is a common root cause. the correct pattern is to register in onResume() and unregister in onPause(). You are guaranteed those will be called when your app pauses / resumes.
Unless you have a really special purpose reason, don't as suggested above use the various methods for manually killing your process. The OS has memory management built into it. Don't try to be smarter than the OS. Android keeps application artifacts (activities, services, etc) in memory even when they are "finished". This allows them to re-start faster the next time. If it needs the memory for something else, it will remove the unused processes from memory.
How are you closing the application? Hitting the back button or the home button doesn't close the application, it just finishes (or pauses) the activity. You have absolutely no control over when Android decides to terminate the process and kill the application.
finish() doesn't actually kill your application. In almost every case it's the exact same as if the user had hit the back button.
ActivityManager.killBackgroundProcesses(yourPackageName) may be what you're looking for.

Categories

Resources