onCreate() and onDestroy() NOT symmetric? - android

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...

Related

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

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.

Confused about this Android Activity life cycle scenario - OnCreate gets called whenever app goes back to foreground

To make things as simple and easy to follow I created a new empty project in Android Studio with only one MainActivity and Hello World text. This could not by any means be a consuming app. I also did override all the important life-cycle methods like onCreate ,onStart, onResume, onPause, onSaveInstanceState, onStop, onDestroy and logged them to see what is happening.
So here is what I am experiencing (in each step the list of life-cycle callbacks is printed)
After app/activity launches (expected behavior)
onCreate onStart onResume
After I press home button / app goes in background (expected behavior)
onPause onSaveInstanceState onStop
After I immediately return / app goes in foreground (expected behavior)
onStart onResume
After I press home button (app goes in background) and I open another app like Facebook and immediately return back to my app I expect it to resume, but instead onCreate gets called.
onCreate onStart onRestoreInstanceState onResume
I find this really strange because I am not low on memory on my device and I have basically empty activity. Is there some flag I can set in the manifest or any solution that will not recreate my activity when I return to it ?
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState, I am specifically interested why onCreate is called when I move my app back in foreground. I've done many apps in the past and I don't remember having this issue before with activities being destroyed so early.
I open another app like Facebook and immediately return back to my app I expect it to resume, but instead onCreate gets called
Apparently, Android terminated your process, either of its own volition to free up system RAM or at the behest of some other app (e.g., task manager). This may also be device-specific, as device manufacturers can tweak how this stuff works, from what I can tell.
I find this really strange because I am not low on memory on my device
Perhaps Android or the task manager disagreed with you. Perhaps your means of determining free memory isn't the same as what the out-of-memory killer uses. Also, bear in mind that Facebook uses some techniques that cause them to use an outsize amount of RAM for their process, so they will cause more of this sort of thing than will a leaner app.
Is there some flag I can set in the manifest or any solution that will not recreate my activity when I return to it ?
No.
That being said, there are a variety of factors that the out-of-memory killer will use to determine what process(es) to terminate to free up memory, including:
process importance (are you in the foreground? do you have a service running?)
process age
process working set size (i.e., memory usage)
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState
I would suggest to all Android developers that they save and restore instance state using onSaveInstanceState() and onRestoreInstanceState(). That helps with configuration changes as well as these sorts of process termination scenarios.
I've done many apps in the past and I don't remember having this issue before with activities being destroyed so early.
Perhaps you did not test them on this device, or on this device and OS version (if you got an upgrade). Perhaps you did not test them in this scenario (e.g., launching Facebook). Perhaps you did not test them with the other apps you have running that might be affecting matters. Since you wrote those other apps, presumably you can re-run your tests using those apps, for more of an apples-to-apples comparison.
You can (and should) make this happen for testing by turning on the "don't keep activities" developer option. You cannot prevent it from happening. This can always happen, and you must handle it gracefully.
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState
That's what you have to do if you want your app to work reliably.
The android lifecycle guarantees some things and provides no guarantees about others. It's guaranteed that if your activity was destroyed, onCreate() will be called before onStart() and onStart() before onResume().
However, in most cases there is no guarantee that your activity will NOT be destroyed once it goes into the background. The reasons are not fully spelled out because this gives google (and individual android distributions) the freedom to modify such things in the future. Part of the downside of having no such guarantee means that just because your activity did not get destroyed in the past, does not mean that in a different version of android, different device, or different circumstance, that it will not get destroyed in the present.
If you must know the exact reason why, I would suggest monitoring the log output very closely, it may contain some clue. But keep in mind that android does not intend for the developer to try to avoid this, only to resume from where you left off when the activity is re-created.

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.

Android Memory Management for Lifecycle

I am trying to determine how to keep my app safe under various Android lifecycle conditions, such as another app being start, phone going to sleep, etc. I understand the lifecycle states and the event methods I can hook into, but I am not sure how memory is handled in regard to things I already had references to. I am well aware that my app may be killed at any time if the OS needs to, but what about individual references? Here are a few example scenarios: if my app is running and the user gets a phone call, or the user starts another app, or the phone goes to sleep. Assuming my app did not get killed, can I safely use my references or will I get random null pointers? I guess what this comes down to is... does Android either kill or not kill and app or will it reclaim some memory (where there are still valid references) from an app without killing it?
Most of the time when the user switches to another app or answers the phone, you app will simply be suspended. When it comes back, onResume() will be called and it will continue on it's way with no issues. References and that kind of thing should be fine. It is recommended that you unregister listeners and re-register them in onResume(), though.
You should always remeber that your app may also be completely killed at any time, so save your data.
The truth is most of the time the application will not get killed in a brief interruption, for example a call or email, but if you want support these situations you should preform cleanup or saving the data in onPause(). When the application comes back it will execute onResume().
References will not disappear until the activity is destroyed, do not worry about NPE in the pause -> resume scenario unless you are doing something very odd.
If you are using listeners or GPS, you should unregister during onPause() and resume it later.

How much time can be taken inside onDestroy() before the activity is killed?

I know my question caption must have sounded really vague. But let me clear it out here.
Say I have an android application over a middleware stack. In onCreate() of my activity, I initialise my middleware modules.
In its onDestroy(), I must de-initialise the middleware. Now my middleware calls may take quite some time to process. So I want to know how much time the onDestroy() function has, and see whether my deinitialisation can take place within that time.
Is it reasonable to keep my de-init in the onDestroy()?
Also, suppose I initialise the middleware in onCreate() of activity A1. On a button click, activity A1 switches to activity A2. In low memory situations, the LMK will kill the activity that has not been in use for some time. In such a case, won't activity A1 be killed? When activity A1 is killed, will all instances I create in A1 also get destoryed?
Regards,
kiki
I believe you are rather confused to ask this question.
In order to get a good comprehension of what is happening, you should take a look at the lifecycle graphs that can be found on developer.android.com:
Activity lifecycle
Background service lifecycle
You will see that Activity.onDestroy() only gets called in the case of a controlled shutdown of the activity - something that happens extremely rarely, as the Android OS can kill your process in a variety of states without ever calling your onDestroy() method.
What and why do you need to de-initialize?
If you're worried about releasing resources, then most of them will get released anyway when/if your process is killed.
If you are worried about saving the user's data (your application's state) then you should override onSaveInstanceState() and onRestoreInstanceState()
If you really want an answer to your question, then here it is:
While it is running onDestroy(), your app has (probably) as much time as it would like to - the fact that it is even running onDestroy() means that the OS did not select it to be killed. But it will most likely not matter: for one, onDestroy will never be run in most apps, and if the OS changes its mind and decides that your app must die, it will kill it even if it is running onDestroy.
http://developer.android.com/guide/practices/design/responsiveness.html:
In Android, the system guards against
applications that are insufficiently
responsive for a period of time by
displaying a dialog to the user,
called the Application Not Responding
(ANR) dialog
The ANR dialog will normally pop up if your application is un-responsive for 5 seconds. As pointed out by jhominal, the onDestroy() method is probably not where you want to do your clean-up/save preferences/etc.
Regardless of where you choose to do this, be it onDestroy(), onSaveInstanceState() or in onPause(), I believe the general 5 second rule will apply. If what you're doing takes more than 5 seconds, the ANR dialog will show and the user can choose to force-close your app.
Edit:
If your application is in the background, it might be (probably?) that it is killed directly without the ANR dialog being displayed if you violate the 5 second rule. But I do not know this for sure, only assuming.

Categories

Resources