Let's assume that I have an Android App with two Activities (Activity1 and Activity2). In Activity1 I declare a public static Boolean foo = true.
When I finish() Activity1 and move to Activity2, I am able to see that "foo" variable has value true
But when the System has low memory (e.g. because there are many apps running on the device) then, when I am on Activity2 I see that the value of "foo" variable is null.
How is this explained?
It's important to note that the life of a static variable is tied to the process not the activity. Even if your activity is destroyed, the static variable will still be alive (which is why you see it's value set to true). It's only when the process is destroyed that the static variable will be freed properly.
This is also one of the reasons you shouldn't use static variables to hold references to activities, contexts, or views. Huge memory leaks waiting to happen.
For your particular scenario, this means that:
Act1 created & set the variable; You've moved from Act1 to Act2
The processes is killed in the BG
When the system attempts to restore you, you end up back at Act2
However, since the initialization of that variable happened in Act1, (which hasn't been initialized) the variable doesn't get set.
If the process is killed then all static variables will be reinitialized to their default values.
So whatever value you have set in Activity1 will not persist
Related
The code is like below:
public class MyTestHelperHelper {
static MyTestApi storeApi = null;
public static synchronized void initial(Application application) {
if (storeApi == null) {
storeApi = new MyTestApiImplImpl();
storeApi.initiImplal(application);
}
}
public static MyTestApi getInstance() {
return storeApi;
}
}
MyTestHelperHelper's initial method is called in Application's onCreate, which is in UI thread. MyTestHelperHelper's getInstance method is called in the Activity's onCreate, which is also in UI thread.
In most case, it works normally. But sometimes, it return null with MyTestHelperHelper's getInstance, which leads to the NPE when I do further operations.
Though the case is rare, I can see it several times in the crash report.
I just don't quite understand why:
There is no write to the "storeApi", except in the initial method.
Both initial and getInstance is in main thread, because initial is called in Application onCreate, and getInstance is called in Activity onCreate.
If my app is in background and process is killed, I think the application will be re-created when bring to foreground, so the initial is called.
Seems the NPE occurs only when
1.process starts without application's oncreate. OR
2.When memory is low, many process data, including static variables, classloaders, classes, etc, are cleaned, except the application instance stays in the process. Is it possible?
It is not possible that a process is newly created and Application.onCreate() is not called.
Whenever a process is created, Application.onCreate() will be called.
However there are certain scenarios where lifetime of static variables could be impacted.
Lifecycle of static variable starts with class been loaded by the JVM and ends with class being unloaded.
A static variable will remain alive as long as one of following won't happen:
The class is unloaded due to low memory conditions.
Note: In this case Application object still persists since it will be the last object to be deallocated. This deallocation cannot be controlled by apps but determined by OS. This could happen if your app is in background and OS wants to relinquish the memory.
The process is killed -> Both static object and Application object are deallocated.
You can use onSaveInstanceState() and onRestoreInstanceState() to save and restore state of your static variable respectively.
My app contains 2 activities both of them depend on some static objects.I'm curious will android terminate whole app and clean my static fields if both activities are destroyed(for instance when device runs out of mem)?
Lets start with a bit of background: What happens when you start an application?
The OS starts a process and assigns it a unique process id and allocates a process table.A process start an instance of DVM(Dalvik VM); Each application runs inside a DVM.
A DVM manages class loading unloading, instance lifecycle, GC etc.
Lifetime of a static variable: A static variable comes into existence when a class is loaded by the JVM and dies when the class is unloaded.
So if you create an android application and initialize a static variable, it will remain in the JVM until one of the following happens:
the class is unloaded
the JVM shuts down
the process dies
Note that the value of the static variable will persist when you switch to a different activity of another application and none of the above three happens. Should any of the above three happen the static will lose its value.
You can test this with a few lines of code:
print the uninitialized static in onCreate of your activity -> should print null
initialize the static. print it -> value would be non null
Hit the back button and go to home screen. Note: Home screen is another activity.
Launch your activity again -> the static variable will be non-null
Kill your application process from DDMS(stop button in the devices window).
Restart your activity -> the static will have null value.
The answer to your question.
yes, if all of your activities are destroyed your application process will be killed.
Credits Samuh
I have an Activity, where I initialize a class member variable in onCreate(). In some case, I need to startActivity() which means this Activity turn into stopped state. When I come back, I need to use the variable.
This works OK in most phones, but I also get some crash from my users because the member become null on their phones. This member just contains some String and a POJO.
Does Android clean up Activity's member variable to free up memory?
Those member variables will be cleared out if onDestroy is called, even if the activity isn't finished. You can simulate this by turning on "Don't keep activities alive" in developer settings. Once that's enabled, start your activity and then pause it (i.e. hit the home button)
To get around this, you'll need to store those member variables in onSaveInstanceState, and then restore them using the savedState bundle in onCreate
In my application, an activity A calls the activity B (via an explicit intent). Lifecycle, B may get killed and recreated etc.
When B is called (from A) it initializes some things. But when recreated it needs to just pick up from where it left. It will finish() some time, then I'm back to A, which might later call B again...
B needs to save a very small amount of data, usually just a few int values. (The rest that I need to restore it is in getIntent() which seems to be still there after the activity has been killed and recreated.) I've heard that onSaveInstanceState and onRestoreInstanceState are expensive and that they are not guaranteed. Plus, I don't need to save the state of views. (For that reason, should I override these two methods with blank ones, preventing the parent ones to get called?)
What's the efficient way to store just a few int values? Should I store the values as static fields of the activity B itself, or of the application itself, or of another class written just for that?
Also, how does the activity B know whether it's been recreated rather than called?
I've heard that onSaveInstanceState and onRestoreInstanceState are expensive and that they are not guaranteed.
They are not particularly expensive. And, for your scenario, they will be used most of the time. The exception would be if your task is not being restarted, such as:
the user got rid of your task by swiping it off the recent-tasks list
at least pre-Android 5.0, your app has not be run in ages and falls off the end of the recent-tasks list
the user force-stops you from Settings
But in those cases you will not be restarting at B, since I assume B is not your launcher activity.
For that reason, should I override these two methods with blank ones, preventing the parent ones to get called?
Not unless you are experiencing actual problems, not just rumors of hints of potential problems.
What's the efficient way to store just a few int values?
For your case, probably use the saved instance state Bundle.
If you cannot afford to lose those values even if your task goes away (and you will not be restarting at anyway), store them in a file, database, or SharedPreferences.
Should I store the values as static fields of the activity B itself, or of the application itself, or of another class written just for that?
No, because none of those will work. You specifically state that your concern is "Lifecycle, B may get killed and recreated etc.". Part of that lifecycle is that your process may be terminated, and in that case, static data members go "poof".
Also, how does the activity B know whether it's been recreated rather than called?
See if the saved instance state Bundle passed into onCreate() is not null. Or, see if a retained fragment exists, if you're using one of those.
What is the Life cycle of static variables in Android?
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.
Android may kill you app if it runs out of memory and all it's activities are in background (not visible). But you activity remains in history and user may activate it again. In this case system will recreate your app and restore it's state.
To deal with this case you should store state of your app and activities in persistant memory (files, database, etc).
More info you may find here http://developer.android.com/reference/android/app/Activity.html#SavingPersistentState
It depends were you define it, for example :
If the process is killed then all static variables will be reinitialized to their default values.
So whatever value you have set in Activity A will not persist. The same goes when an activity is destroyed.