This is a follow up question to one of my previous questions.
I have a LoadingActivity which loads some graphics needed by all Activities and store it into a static class. I try to not load the LoadingActivity over again when pressing HOME and resume the app since it takes a lot of memory and runs out of it after several times whereby the graphics are already loaded, so no need to start the LoadingActivity again.
My question is, how long does the static class live? Can I rely on it's availability after resuming the app, or may it be here since Android kills it due to memory issues or is it always here as long as the vm runs (that means as long as the phone is running)?
As Simon points out, "static class" means different things in different languages, and Java does not have anything quite like the static classes in some other languages. But I don't think that's what you're talking about. You seem to be asking whether objects referenced by strong static references can be garbage collected. If so, the answer is no.
A class is represented by an object of class Class which is reachable via its ClassLoader. Anything referenced by the Class will therefore be reachable as long as the ClassLoader is reachable, which in the case of the system classloader is as long as the Java/Dalvik VM exists. But that is not as long as the phone runs, since an independent VM is created for each app. The entire process and VM in which an app is running may be killed whenever the app is in the background. When you return to the app, its classes will be reloaded.
If static fields are really the best choice, as opposed to a ContentProvider or foregound Service, then every time your app resumes you will need to check if the static references have been initialized and re-initialize them if they are null.
Related
To maintain global variables, the Application class is extended. What happens to these variables when the application is put in the background and at some point, the OS wants to free up the resources? If the onTrimMemory() call is ignored, then does that mean that all of the variables are preserved? Unlike the Activity, which may have to rebuild some of its state.
Thanks,
Gary
To maintain global variables, the Application class is extended
You are also welcome to use classic Java static data members.
What happens to these variables when the application is put in the background and at some point, the OS wants to free up the resources?
The only "resources" that "the OS wants to free up" will be your entire process. Your static data members or other singletons (like a custom Application, or your ContentProvider instances) will remain in memory until such time as Android terminates your process.
If the onTrimMemory() call is ignored, then does that mean that all of the variables are preserved?
Yes, until such time as Android terminates your process.
Why I shouldn't use static objects in an Activity or don't make static calls to an Activity?
A more reasonable statement would be saying be extremely careful about using static variables in Android.
You can use them, but be aware that you application can and will be killed by the OS, and restarted when the user returns to the app (i.e. maybe from the recent apps list). This results in your application having many different entry points, and you can't assume the static variable will be initialized.
For example, setting a static variable in your application's first Activity, and assuming it will always be set is a big mistake.
Also, be cautious about storing anything that has a reference to an Activity as a static variable, because this tends to be a common source of consuming memory unnecessarily. For example, storing a View in a static variable is almost certainly a mistake, because it will prevent an entire Activity from being garbage collected if not cleared out.
It is a general good practice to avoid making things static that don't need to be since they increase the chances of memory leaks. If you're always holding a reference to some data the GC won't be able to free it.
I have some unclear situation:
Will static singletons be garbage collected after last reference holding Activity has been destroyed? Because there is no more references in Application to singleton instance. Can I then rely on singletons?
By official Android doc:
There is normally no need to subclass Application. In most situation,
static singletons can provide the same functionality in a more modular
way.
By some post:
https://web.archive.org/web/20160729201921/http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
While developing an application, I found
that sometimes some static variables bound to activities happened to
be uninitialized even though they’ve previously been initialized! I
thought that when a static variable is initialized it stays so for the
entire life of the application, but this doesn’t seem to be the case.
In another words, if nothing is holding a reference to my static singleton class, what's to prevent it from being garbage collected and destroyed?
No, because if it's a singleton, it's stored as a static field in its class, and usually singletons are not destroyed by clients, ie you wouldn't put a static method deleteInstance() which sets the reference to null so that if nobody else uses it, it's eligible for garbage collection. For static fields, garbage collection will happen when the classloader which loaded the class is discarded.
For this reason, the keyword static itself may cause memory leaks, if it references Activity objects, so you should be very careful when using it.
Yes. Every time you leave your application (for example your app opens the camera app to take a picture, or opens the browser to open a link, or the user just pushes the back button) there is a possibility that your Application object will be destroyed and recreated when you navigate back to your app.
You should initialize any static variable in a static {} block in your custom Application class if you have one, or in your Activities to ensure they won't be null.
Note that it is more probable to experience this issue on devices with weaker hardware, lower memory, but you should expect it can happen on any device.
Bottom line is, in android, don't expect that your static variables will stay in the memory at any time. Always check if they exist and reinitialize them if necessary at the right places.
EDIT:
I know it has been a long time, and I totally forgot about this thread, anyway, here is the source from the official Android lifecycle documentation:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
You can not control when exactly Java objects become garbage collected. An object becomes eligible for garbage collection when there are no more (non-circular) references to it. With Android, further, you can not control when your Activity gets removed from memory.
singletons are supposed to represent something which always exist.
You can't force any object to be garbage collected; you can request that the garbage collector runs with System.gc() but it's only a request.
If you want to make a "singleton" eligible for garbage collection, you'd probably want to have a method to set the static variable to null (and hope that nothing else had taken a copy of the reference). Obviously the next time anyone asked for an instance, it would need to be recreated. at which point it's not really a singleton, of course.
All singleton object will stay even if the activity is destroyed.
I am very familiar with the Android activity lifecycle, but I feel like I am missing something that should be pretty obvious here.
I have a multi-activity Android app; it uses static variables (in the application class) to keep a handle on the various objects that are used across the different views. The problem occurs when the app is paused (exited) and Android (presumably) cleans up memory to maintain foreground processes. When the user resumes the app, it occasionally (not always) seems to come back and resume in the Activity that the user left, but with the static variables nulled. Even worse, the activity sometimes seems to resume with the static variables still present, but with internal variables in objects nulled.
I eventually implemented a simple sanity check, which checks that the statics are not nulled (and also the most vital inner variables of relevant objects) and returns the app to start if it fails. This did cut down on a lot on the problems, but I still see the occasional issues with this, as it is simply not practical to check everything for every resume().
What I really need is for the app to restart from scratch if the Android OS decides it needs to clean anything non-GC from memory while the app is inactive. I feel there should be a graceful way to do this, but haven't noticed anything in the documentation.
Any thoughts? How do others avoid this problem?
Using the Application class for preserving state can result in unexpected behaviour if Android decides to kill your process completely. Check out this answer to a similar question
i.e. you should probably use some sort of persistence (SharedPreferences or some DB) in your Activity lifecycle callbacks.
In my application, I use a subclass of the Application object to store some references to complex objects I need to access from all of my activities. When my app starts, the startup activity checks one of these references, in this case a Location, and if it is null, it starts the LocationListeners which populate the reference for further use.
If I back out of the app to the launcher screen, and re-launch it, the Application object still has the reference from the previous use a few moments prior. This is fine, and is what I'd expect, but I'm curious how long the Application object is kept around once I've back'ed out of my application? (onDestroy() has been called on all activities, nothing in the stack.)
When is it finally killed? I know it does finally get killed as when I've not used the app in a while, it will search for location on startup (indicating the aforementioned null reference.)
(Also, is storing refs there like that a good idea?)
Thanks in advance gang! :-)
It stays around as long as the application is in memory. It only finally goes away when either someone forcible terminates your application (either using a task killer or from the application settings) or when Android decides it wants to reclaim the memory that your app is using (and this typically only happens when your app has been closed for a while and the phone is running low on memory).