Can anybody confirm the following regarding the android application lifecycle?
1) When application is in foreground the memory will contain instance of the Application object, instances of all activities (not killed) and all the object references that are referenced from one of the root's (haven't been garbage collected)
2) When application goes to background, at some point the Android Framework can:
a) Kill the whole process given to the purpose of the application which will essentialy erase all the objects from the memory
b) Kill ONLY (so essentialy no other object reference will be deleted) the activities (by finishing them and in essence any fragments as well) saving their states and creating the Activities Stack and leaving anything else (Application object, any other static objects, references that are reachable from any of the roots).
I'm mostly interested in 2b, but I would appriciate confirmation on all of these points as I'm trying to grasp mentaly the whole concept from start to finish.
If you are looking for official confirmation then better ask Google only :).
but i feel after reading this you will get a better understanding of these concept.
Android memory management
android process lifecycle
Answer for 1st question:
yes confirm using DDMS.
answer for 2a question: yes OS can kill process any point of time when needed memory for other process which will result into killing all object related to process.
answer for 2b questiong:
From official documentation
Process Lifecycle 3. A background activity (an activity that is not visible to the user and has been paused) is no longer critical, so the system may safely kill its process to reclaim memory for other foreground or visible processes. If its process needs to be killed, when the user navigates back to the activity (making it visible on the screen again), its onCreate(Bundle) method will be called with the savedInstanceState it had previously supplied in onSaveInstanceState(Bundle) so that it can restart itself in the same state as the user last left it.
Yes you are mostly correct about 2b).
If an activity is paused or stopped, the system can drop the activity
from memory by either asking it to finish, or simply killing its
process.
However there are instances where onSaveInstantSate isn't called:
Note that it is important to save persistent data in onPause() instead
of onSaveInstanceState(Bundle) because the latter is not part of the
lifecycle callbacks, so will not be called in every situation as
described in its documentation.
Android Docs Source
You can request android to always destroy activities on background by enabling the following developer option. If you are debugging your app you should be able to step through the life cycle methods and see what is happening.
Settings -> Developer options -> Apps -> Don't keep activities
There is no typical life-cycle for application exists. Application object lives in memory until it is not being killed either by Android itself or by manually by user.
For the above points, here are your answers:
1) This is true.
2) a) That is also true.
2) b) When application goes background, you can only save the data of the current activity that was in foreground. Also, when you kill the application it self (by removing it from recent list), all the activities in the app stack and their saved data (not persistent data) got killed as application is the base for all the activities.
1) When application is in foreground the memory will contain instance
of the Application object, instances of all activities (not killed)
and all the object references that are referenced from one of the
root's (haven't been garbage collected)
> There will only ever be a few such processes in the system, and these
> will only be killed as a last resort if memory is so low that not even
> these processes can continue to run. Generally, at this point, the
> device has reached a memory paging state, so this action is required
> in order to keep the user interface responsive.
2) When application goes to background, at some point the Android
Framework can:
.
a) Kill the whole process given to the purpose of the application
which will essentialy erase all the objects from the memory
> These processes have no direct impact on the user experience. Provided
> they implement their Activity life-cycle correctly (see Activity for
> more details), the system can kill such processes at any time to
> reclaim memory for one of the three previous processes types. Usually
> there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
b) Kill ONLY (so essentialy no other object reference will be deleted)
the activities (by finishing them and in essence any fragments as
well) saving their states and creating the Activities Stack and
leaving anything else (Application object, any other static objects,
references that are reachable from any of the roots).
Partially as in point 2.a.'s explanation
> Usually there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
Source - developer.android.com
Well this thing depends upon how Android OS operates. Android Device is an embedded System but works almost same as a PC and when I say Android as an OS, it will definetely have all the features of an OS. The thing which you are pointing upon is the Memory Management and Scheduling feature of Android OS.
MMU(Memory Management Unit) logically give preference to currently executing task i.e ur launcher or any other Application which u r working upon. Two things I want to answer which can help u bit more:
Views (whether xml generated or Javacode generated, they are dynamically generated.).
Android OS runs all apps as a process with sub processes(Activities) on a Dalvik Virtual Machine.
All your Activities before they are created they are null, when they are created then their instance is generated. Upon opening them again their saved instance is again viewd(Concept of Singleton Design Pattern).
So let me tell you that I don't think that both of the options are right. What I beleive is following:
1. View will always be generated dynamically.
2. Instance will be saved in Memory.
3. On background going of Application the whole process with instances available will be their in Memory.
Ok, during my search quest in recent weeks I was able to get some more information and now I can answer my own (and hopefully for others) questions:
1) Correct
2a) Correct
2b) False. The android framework, if in need of memory or if due to some other reason it has to "kill/reduce" the application it can do so only by killing the whole process that is dedicated to that application. The android framework can neighter kill chosen activity(ies) or kill all activities but leave all other objects alive (like Application object, singletons etc.)
Related
Please note the following vocabulary to avoid confusion
1) When I say reinstantiating an activity, I mean Activity.onCreate(bundle)
2) When I say starting from scratch an activity, I mean Activity.onCreate(null)
(Although I am not sure it makes a difference) For the purposes of this post, please assume that the Android applications I am interested in all have their activities launched in the same task
How does Android go about freeing memory from apps?
Lets say I have a phone. I am using many applications at once. I got bored of the current Snapchat application. So I press the home button and open Facebook. Note that I did not press the back button, and so Snapchat lives on in the recent apps overview.
Suddenly for some reason the phone is very low on memory and needs to start forcefully freeing up some from background apps.
Will the Android OS kill some activities of Snapchat in order to free memory
Will the Android OS kill all activities of Snapchat in order to free memory
How does Android go about managing "killed" apps?
Now lets say I want to go back to Snapchat. I hit the overview button and select Snapchat from the scrolling list of recently used apps.
Will the Android OS reinstantiate some activities of Snapchat
Will the Android OS reinstantiate all activities of Snapchat
Will the Android OS reinstantiate zero activities of Snapchat and just starting from scratch with the initial launcher activity.
TL;DRD: all activities are killed.
The ActivityManagerService doesn't seem to kill anything anymore (it just forces GC calls and dispatches trim events).
if (false) {
// For now we won't do this; our memory trimming seems
// to be good enough at this point that destroying
// activities causes more harm than good.
if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
&& app != mHomeProcess && app != mPreviousProcess) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
// For these apps we will also finish their activities
// to help them free memory.
mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
}
}
Though when (if) it did try to kill something it would kill the whole process of a background app (it would simply call kill -9 [PID]). And since by default all your activities are run under one PID they all get destroyed when a process dies.
The same goes to the OOM and Low Memory Killers - the two operate with processes and make no distinction between your activities.
Please note, however, that some people claim that Android sometimes kills particular activities one by one on low memory. I failed to find any evidence of that in AOSP.
==============
Now, about restoring your app. I might not be an expert here cause this is connected to the Android's "Tasks and Back Stack System" which is way trickier than their tutorial videos make it seem.
The operation starts with calling ActivityManager#moveTaskToFront(...) and it eventually leads us to ActivityManagerService#moveTaskToFrontLocked(...)
There the OS will try to retrieve the stored task record associated with your app. If your app's been destroyed, the manager will have to go to ActivityStackSupervisor#restoreRecentTaskLocked(...) and if all goes well it's gona find the task and the back stack and do this for every activity in the task:
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
mWindowManager.addAppToken(0, r.appToken, task.taskId, stack.mStackId,
r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
}
The same method (WindowManager#addAppToken(...)) is called when you start a new activity and it goes with a comment:
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
So my guess is that when the OS restores an app it recreates the activity stack fully but only the topmost activity actually actually gets restarted. I guess, it's easy to set up an experiment to find out if I'm right here.
=======
One more update :) Yep, these two methods (ActivityStackSupervisor#resumeTopActivitiesLocked() and ActivityStackSupervisor#resumeTopActivityLocked(...)) are called a bit later. Though I really don't undesratnd why they resume activities in more than one stack - as I said, I'm definitely not an expert here.
Considering this scenario: If I created an activity and it moves to the background and this activity contains a Fragment which is set to setRetainInstance(true) then the Android OS might at some point still decide to shut down the activity's hosting process in order to free memory.
Then the Activity's state is saved via onSaveInstanceState(Bundle) where - as far as I understood - the related Bundle is written and to the file system to survive the process shut down. (thus the requirement of objects in the bundle being Serializable). Later, the applications state can be retrieved in a new process via onRestoreInstanceState(Bundle).
In contrast, my Fragment is allowed to contain variables which are not necessarily Serializable. Therefore, I figured, the Fragment cannot be stored on disk like the Bundle is. So what happens to my fragment when the process gets killed?
I was wondering about this reading the developer's guide (http://developer.android.com/guide/components/processes-and-threads.html):
A process holding an activity that's not currently visible to the user
(the activity's onStop() method has been called). These processes have
no direct impact on the user experience, and the system can kill them
at any time to reclaim memory for a foreground, visible, or service
process. Usually there are many background processes running, so they
are kept in an LRU (least recently used) list to ensure that the
process with the activity that was most recently seen by the user is
the last to be killed. If an activity implements its lifecycle methods
correctly, and saves its current state, killing its process will not
have a visible effect on the user experience, because when the user
navigates back to the activity, the activity restores all of its
visible state.
I understood the above killing such that the VM instance is shut down and the state of the process is written to the file system (here comes the Bundle into play). Later the bundles are read for resuming the process. Since the retaining of fragments is not concerned with life cycle methods and since I would not know how to retain e.g. a pointer to a network connection (you should of course never have such a pointer in a fragment anyhow), I was wondering if the fragments are still restored if the process is shut down in the meantime. I concluded that they surely needed to be recreated and that the life cycle methods are therefore to be preferred over setRetainInstance(true) whenever possible.
Does this assumption make any sense?
Sounds like you're mixing up two concepts here.
Saving state across Configuration Changes does not involve serialization. If you request setRetainInstance() for a Fragment then that means it will fully stay in memory and not be re-created only for configuration changes. A similar mechanism is available for Activity objects but they need to explicitly define an Object which is going to be saved. This works via Activity.onRetainNonConfigurationInstance(), not via onSaveInstanceStae().
The other mechanism involves serialization and possibly (maybe not always, not sure) file system I/O to be able to reproduce state information even if an Activity/Fragment is destroyed (which happens independently of its hosting Process, btw). This works via Activity.onSaveInstanceState() and Fragment.onSaveInstanceState().
Of course, you can use the second mechanism for the purpose of the first, thus slowing down the way your app deals with configuration changes. Depending on your internal state, the slowdown could me marginal of significant.
Regarding your questions.
"My Fragment in contrast, is allowed to contain variables which are not serializable." Well, the same is true for your Activity. It can contain non-serializable objects which can be saved across config changes as described above.
"the fragment cannot be stored to disk when a process is shut down and must be recreated when an activity was restored." No, both mechanisms are available for both object types.
Hope I could contribute to clarifying this a bit.
Edit after your first comment.
Regarding the comment:
"onRetainNonConfigurationInstance is deprecated": Yes. I mentioned it for demonstration purposes because of a specific wording in your question. Also, with Android 2 devices having a 46% market share as per today (official Google figures), this method will definitely stay around for a very long time, deprecated or not.
"My main concern is about what will happen to the fragment instance when my hosting process is killed and removed from the memory": Your fragment instance will be removed from memory and there's of course no way it is restored as-is with its complete internal state automatically. This is only done when you setRetainInstanceState in the case of config changes. (But note that this relates to the Instance, in other words, the full object.)
Regarding your edit:
Once more, yes, your Fragment's Bundle will be stored and restored to/from the Bundle regardless of setRetainInstanceState if you use Fragment.onSaveInstanceState() for this purpose, for everything that makes sense.
It is not true that "all of its visible state" will be saved as the text you refer to claims; for example, the visibility attribute will not be saved. Whether that's supposed to be a bug or a feature I don't know, but it's a fact. But this is only a side remark; UI elements will save most of their relevant state.
"the state of the process is written to the file system": No! The state of objects which are able to save their state to a Bundle and actually implement saving their state will be saved in a Bundle, this means that you must provide such information yourself if you want your Fragment to save some state information. Also, again: No, this does not only relate to killing the process but also to deleting Activity and Fragment objects which are not visible; like the last Activity shown -- the Process may well stay alive.
"bundles are read for resuming the process": No, the Bundle will be read to pass it to the re-construction of Activity and/or Fragment objects, there is nothing done automatically in this process (except library objects which save their state also restore their state), but Android does not "resume" the "Process" from these Bundles.
"Since the retaining of fragments is not concerned with life cycle methods": Again, I think you're mixing up the two concepts. The "retaining" of a Fragment is only performed upon configuration changes _IF_ you request it via setRetainInstance, but we're mostly talking about the re-creation of Fragment objects from a Bundle here, which does involve the life cycle methods as documented by Google.
"I would not know how to retain e.g. a pointer to a network connection": Again, this must be a statement based on your mix-up. Of course you can keep a reference to a network connection upon config change (as requested per setRetainInstance) because when that happens, everything is simply kept in memory. Also, even if your Fragment gets deleted (because it became invisible) and your process is still there (because it shows the next Activity), you can (and should) keep references to objects which are expensive to re-create, such as a network connection, in your Application object, which exists as long as your process lives (more or less). It is only when your whole app is killed by Android that you lose everything, but the serialization we're discussing happens much more often.
Your conclusion:
I concluded that they surely needed to be recreated and that the life cycle methods are therefore to be preferred over setRetainInstance(true) whenever possible. Does this assumption make any sense?
Unfortunately not, since you are mixing up completely independent concepts.
I'll give it a final try:
You will want to keep a network connection reference which you need throughout your app in your Application object because it would be a lousy user experience if you created it from scratch on a regular basis throughout your app.
Your Application object will only die if Android kills your app.
Your Activity and Fragment objects will be deleted from your app regularly when the user moves forward within your app.
When the user presses "back", Android will re-create Activity and Fragment objects from Bundles using lifecycle methods. Saving something in a Bundle makes sense if you have expensive computations to do to re-create the internal state. You can live without the Bundle mechanism because Android will always save the Intent so if you don't do anything then you'll start without saved state.
When a configuration change occurs, Android lets you optimize user experience by keeping objects in memory across the config change. Here, Activity life cycle methods get involvwed and it's up to your implementation to use the saved data effectively. For Fragments, this is where setRetainInstance' comes into play: YourFragment` will survive the config change in memory if you set it.
As I understand a singleton cannot be expected to hold persistent data in Android apps because an app may get destroyed and recreated several time in the app's "apparent lifecycle". This in itself is not a problem for me. The problem comes with what exactly happens when an app goes through this destroy -> create process.
I have read on forums that the app will be recreated in a new process, and I assume that the old process with all its memory management will get destroyed. However does this mean that it is up to the developer to clean up all singletons and logical trees with nodes holding mutual references? Or does the destruction of the process automatically cleans up everything? I am not an experienced java developer, so a lot is still unclear to me about the GC.
The specific project I'm working on runs only a single app throughout the uptime of the device. In desktop terms there would be no danger of memory leaks through singletons since the application only shuts down on device shutdown and lives in thesame process the entire time. Android makes it more difficult however.
On a side note, what's a good memory leak detector for Android using the emulator?
Basically you must avoid to keep referenced to UI elements. That UI elements are bound to the context of the activity which could be destroyed.
If you really need a singelton than extend Application class for enforcing that. This instance won't be destroyed when a activity closes, or on rotations and so on.
You should also know that you can handle that events in your code. That means that your activity must not been restarted. IMHO it makes in almost no case sense to restart an Actity. To implement that you need to add the configChanges attribute to your manifest. I personally use this config:
<activity android:configChanges="orientation|screenSize|keyboardHidden" ...>
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).