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.
Related
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.
I'm new to Android development. I'v developed an android application which needs to store the connection/data even after 1 hour. Currently I have all the data and the connections(chromecast mediaplayer) in a singleton class. But, when the user puts the app into the background for about an hour, the activity is destroyed so the connections,data etc are lost causing my app to crash when re-launched.
I've read up on the android services, Can I use these services to hold the singletons so even when the activities are destroyed I can have data binded back to the views when re-launched?
Or is there a way to make sure that the activities are not destroyed when android decides to do a cleanup?
Please advise
Thanks.
I think you might misunderstand what an Android application is.
Your application is a bunch of components that run in a single Linux process. Components come and go, within that process. You have absolutely no control over the lifecycle of the process itself.
The answer to part of your question is that "yes" a Service will stick around after an invisible activity is destroyed.
When an Activity becomes invisible, it gets destroyed. If your process is not doing anything else, then the process is likely to be killed too.
If your process is also running a Service, it is less likely that it will be killed. It is just less likely, though. The process will eventually get killed. When it does, your singletons will be gone. There is nothing you can do to prevent that. So the answer to the second part of your question is "no". You cannot depend on singletons in your service to be around when the process is relaunched
You might look into using the Application object. Its lifecycle is roughly the same as that of your process. It will not live forever but it will be around whenever any other component of your application is around (except ContentProviders).
It sounds like you want to keep connectivity to a chromecast device around when your application is in the background. Obviously services can be helpful but I have a few comments that may come handy:
Services can be killed by system but based on how you have set them up (e.g. the return value of onStartCommand()), they can be restarted by the system. When that happens, you cannot expect that your dynamic data is still there (for example your singleton). You need to include logic to recreate what you need again (for example, rebuild your singleton)
Phone can go to sleep when left for a little while (or user can lock his/her phone), so when phone goes to sleep, wifi may drop after a little while, based on the phone settings and the build on your phone; some do this more aggressively and some not (even if you hold a lock, it can still happen). The point is that you have to assume that it may happen. Even if you have a service, your Cast connection will go down due to wifi loss, so the proper way to handle things is not to try to keep the connection up all the time (since you can't) but is to have logic to re-establish connection when circumstances is right. In order to do that, you need to preserve enough information to be able to bring things to the state that they were. Your logic should also be intelligent enough not to reconnect if it shouldn't.
Android O.S can destroy any activity , when it is low at resources it destroys any activities to make more space for other apps.
But you can use background service to hold your singleton
You can use this link to create your background service
More concretely: Is it safe to place the canceling of a task in onDestroy? Also, is it safe to use onDestroy for unregistering receivers and freeing up resources?
My aim is to make sure that my task is canceled/destroyed when the Activity is destroyed, but not before.
onDestroy():
is called when the activity is destroyed and resources must be
released.
is NOT called when the activity is destroyed in a hurry (when the
system is low on resources etc).
The first case is clear: I do all cleaning in onDestroy and no problems arise. The second case is a bit of a problem though. When the Activity is destroyed and onDestroy is skipped (so I don't cancel my task), could it happen that the task continues execution, then completes and tries to update the dead Activity, so the app crashes?
We come to the real question:
When an Activity is killed and onDestroy is skipped, is everything attached to that Activity automatically destroyed? (Is onDestroy skipped only in case that everything will be wiped out altogether? Tasks, registered receivers etc)
If onDestroy is skipped does this mean that the whole app is being killed?
Let's focus on onDestroy(), because the solution is not in onPause() or onStop(). Arguments:
onStop() could be skipped when the Activity is being destroyed, just like onDestroy
onPause is called too early and too often, so it is not appropriate for the use case. Examples:
Screen lock: onPause can be called when the device screen is locked. Very often this happens like a screensaver and the user unlocks immediately because he is standing there looking at the screen. Canceling tasks and stopping everything my app is doing in such a case will only degrade user experience. I don't want my app to choke and misbehave just because of an incidental "screensaver".
In an example app I have two screens that are Activities. The user can quickly switch between them. In this app users tend to switch screens often and quickly.
Navigation: One of the screens has a map which receives location updates from the system. It records a precise graphical log of the changes in location (route), so it needs to run constantly until the Activity is closed. Normally I would register and unregister any receivers in onResume and onPause. However, this would make the app very unusable, as the updates on the map will stop every time the user navigates away. Therefore, I would like to unregister the receivers in onDestroy.
Loading list: The second screen has a list that shows data from a webservice. It takes 4 seconds to download the data. I use an AsyncTask and I know I should cancel when necessary. It should not be canceled in onPause, because it should continue loading while the user switches between screens. Therefore, I would like to cancel it in onDestroy.
There can be many more examples. Some of them might not be totally appropriate in everyone's opinion (you might even suggest using a service instead of AsyncTask). But the idea is important, and all of them have the same idea: keep on doing work that's specific to the Activity, while the Activity is paused, but ENSURE to stop doing it when the Activity is destroyed. (It does not matter whether I am using an AsyncTask or a Service. In either case, the work should be stopped when the Activity is destroyed.)
P.S. If the answer is that it is not safe to do the clean up in onDestroy, this would mean that the Android framework requires us to stop everything we are doing in onPause. And then I would not see any reason for using onDestroy...
I would like to refer you to this baby: http://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int)
Essentially it gives you all the places where the system finds it useful to cancel tasks and clean its memory:
Please take a closer looks at the following 2 cases:
TRIM_MEMORY_UI_HIDDEN - the process had been showing a user interface, and is no longer doing so.
TRIM_MEMORY_COMPLETE - the process is nearing the end of the background LRU list.
Which are the cases for most of what you asked.
In the same method you can also catch TRIM_MEMORY_RUNNING_CRITICAL which will alert you to a case where the system has no memory and special actions must be taken immediately.
This method has made my development life much better in similar cases.
If you just need to do some cleanup, no matter how the activity is closed, you should be able to use a combination of onSaveInstanceState() and onDestroy(). One of those should be called no matter what. Maybe have a boolean cleanupDone in your activity, which is set whenever one of the two finishes.
Concerning saving of user data, have a look at Saving Persistent State:
Google suggest a
"edit in place" user model
That is: save as soon as the user creates new data, at the latest in onPause(). This does not mean that you need to recreate the data in onResume(), just that it should have been saved.
By the way: onStop() can be skipped only on pre-Honeycomb devices, that is, as of June 2015, less than 6 % of all devices. Still, onSaveInstanceState() should be called if either onDestroy() or onStop() are omitted.
As far as I gone with android,
1 When your apps crashes every resource relevant to it are destroyed.
2 When the device changes configuration resulting the Activity to be destroyed and recreated.
3 When apps running in background and Android kill it due to running on Low Memory
apart from these the other callback method are called i e
1 when another Activity come in front , or your device locks ..etc
In all case according to your requirement you can release all your resources in onDestroy and cancel the Thread and Asyntask and stop all the services etc .if you want your task remain paused and alive while on destroy called then you can save the configuration and retain it while onCreate is called again by check is null or not.
This doesn't appear to be well documented or I missed it, so before I run a bunch of my own tests I was wondering if anyone already knows the answers to some of these questions.
First off, when I say "Application" I am referring to extending the Application class. http://developer.android.com/reference/android/app/Application.html
The questions I have are as follows, some are related.
When an a user leaves an Activity from within the Application, and goes to the Activity of another application, does the Application somehow get paused as well, even though it doesn't have an onPause()? Or does it continue to live unpaused until all of it's activities are destroyed?
when does the Application stop? When all of it's Activities are destroyed?
Is there ever a chance that one of the Applications Activities could be running without an instance of the Application, or will the Application class always exist if one of the Activities does?
If there is some process running on the Application, and it's Activities are all paused, will that process continue to run?
Is the Application effected by rotation in any way or does rotation only change Activities?
Thanks
As you say the application does not have onPause so nothing happens to the application. When onPause gets called in your Activity nothing special happens, your Activity continues to run and can do whatever it wants including run new threads, timers can go off, whatever.
I believe what you are asking is: when is an Application destroyed and when the onTerminate method in an Application called? The answer is hard to pinpoint and is up to the system, it does not necessarily happen when all activities get onDestroyed called. In fact even when onDestroy is called, your Activities aren't necessarily garbage collected. When the system gets low on memory the process that your Application lives in can be killed, meaning your Application will disappear; onTerminate may or may not be called. At that time all the Activities, Services, etc, are killed too.
The Application is always instantiated first, an Activity must have an associated Application, just like how you define it in the AndroidManifest.xml.
Processes never pause in Android, the onPause method does not actually really do anything other than tell you to pause things in your app. Other than that the process keeps chugging away, your threads keep running, even the main thread receive Intents with a BroadcastReceiver.
The Application gets rotation callbacks in the Application's onConfigurationChanged(). I'm not sure if you can disable that since there is no configChanges attributes supported by application tags in the AndroidManifest.xml.
A good comparison to Application is static field in any of your classes. The static fields will live as long the process is not destroyed, just like the Application. Static fields can be accessed by all Activities, Services, etc (assume the static fields are public), just like your Application.
Good Luck!
Jacob
The easiest way to understand this is to just forget that Application exists. Application has nothing to do with the application lifecycle. It is just a global on a process, that can be useful for some things, but is not needed for anything. Everything about how an application runs revolves around the Activity, BroadcastReceiver, Service, and ContentProvider components declared in its .apk.
An instance of Application can continue to exist after your last Activity is destroyed. Even if ALL activities are gone (ie. have all had their onDestroy methods called), the Application instance could still exist.
This application instance could be "re-used" for what you might otherwise think are two separate runs of your application.
This is all explained in detail here: http://developer.android.com/reference/android/app/Activity.html. If you read through it, you should understand everything.
Real quick:
Every activity has an onPause. You can choose not to override it, but it'll get called nonetheless. As soon as you switch away, onPause will be called.
Define "stop". Define "Application". The process may linger around forever, but it'll simply sleep and wait until one of its activities is started.
It's impossible for an activity to exist without being instantiated.
Every code executed runs in a process, so there's always one process for your app. The process will continue to exist after you switch to a different app, but it'll be in sleeping state. Android could at any time kill the process if system resources run low.
Every time you rotate the screen, your activity will be destroyed and recreated, unless you specifically disable that.
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.