I noticed this behavior while developing a simple Android game which has 2 activities.
The game has 2 activities, the first is a screen which allows the user to select the opponent type, level etc. and the second the actual game screen.
The second activity creates an object of a GameManager class which handles all the game processing.
This GameManager class also creates a CountDownTimer which it starts to prompt user input (on timeout the game is defaulted to the opponent).
I've noticed that if the user exits the second activity (returns to the first) and then launches a new game again, the previous timer is still running until completion.
I've handled this by explicitly cancelling the timer (from the onDestroy() of the second activity) as just setting the timerobject to 'null' did not cancel the timer.
However I'm curious as to why the previous timer was running even after my activity was exited the first time? Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited? Would be great to know the reason behind the observed behavior?
TIA
Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited?
This isn't how Garbage Collection works. The GC isn't responsible for 'deleting objects' - it's responsible for picking up 'orphaned' objects and freeing their resources. Even then, a GC isn't guaranteed to get to all of the orphans in a timely manner.
Further to that, any objects which may be 'system' objects and need to be released explicitly may never be released if your code doesn't do it. Other issues with GC may include creating objects which other threads (other than the Activity which created them) may have a reference to.
You mention your 'timer' but don't explain what sort of class you are using for it. I suggest read up specifically about that class and see what the implications are for ceation/deletion (possibly explicit 'release' of resources).
GC is a very grey area on any platform. With Android it's normally pretty immediate but with the nature of the Activity life-cycle it's very difficult to predict what will happen.
In general make use of onCreate, onPause and onResume within Activities and also things like savedInstanceState and SharedPreferences to keep track of what is going on.
CountDownTimer is not bound to an activity as you already found out. A hint to lookout for in these cases is that a class does not receive any Context in its constructor. Hence it can't be bound to an activity.
Related
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.)
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.
I have a complex app that has background threads (that could be in a service) which, when they receive data from the internet, need to notify my main display activity (to update on of several status indicators). All run in the same process (I see no reason to do otherwise).
However, in some circumstances, these events are frequent - 5 per second. Also, the events may occur when the activity is not-visible or even destroyed. I think the only thing novel about this question is the issue of efficiency. I still target the G1, for example.
There are a number of methods mentioned in this thread, but I don't know which of these are efficient enough, and will work if the activity is destroyed. Those methods are the "Android way" which I would prefer to follow.
I have three ugly anti-Android ways that work, but they also have drawbacks:
Have a thread in the activity that is waits on a semaphore, and when released, does the update. Disadvantages: extra thread, how to handle several event types
Like #1, but use a concurrent blocking queue object. Disadvantages: extra thread, same type of event may end up in the queue multiple times (not good)
Keep a static reference to a handler on the activity, and use that to run an updater. Disadvantages: (a) may leak a reference to the activity? (b) what happens when the activity changes state? (c) multiple runnables could end up there when only one is needed.
Also, the events may occur when the activity is not-visible or even destroyed.
If your activity is destroyed, there is nothing to update. If and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
If your activity is in the background, there is nothing that needs to be updated, either. Again, if and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
The ONLY time you need an activity to be notified of events in real time is if that activity is in the foreground. In that case, any of the solutions I outlined in the answer you linked to could work. The binding option or Messenger are probably the lightest-weight solutions.
I have a complex app that has background threads (that could be in a service)
Not "could be" -- "must be", if they are to live beyond the scope of any given activity instance.
I have three ugly anti-Android ways that work
None of those work without potential memory leaks.
I have a fairly complex app -
The UI Activity launches a Service and sets up 2 way AIDL callbacks so the two can communicate.
The service runs forever (unless hits 'off' button in UI Activity).
The problem is when the user exits the Activity, the Activity memory is not released.
-The amount of memory used by my app is the same even if the UI Activity has been closed.
-The heap still shows mapTiles and other UI crap on it even if the UI Activity has been closed.
So my guess is somehow the Service is holding references to the Activity. I know the many articles warning about leaking the Activity Context. The Service only references the Activity through a Weak Reference stored at Application scope. (a class that extends Application)
Is there any way to find what specifically is referencing the Activity? The dominator tree shows mapTiles and ListView layouts eating all my memory... but I can't find the reference to the Activity which is keeping that stuff alive.
Also, is there a way to dump an HPROF heap dump thing if OutOfMemoryException occurs?
The problem is when the user exits the
Activity, the Activity memory is not
released.
There is no "exit Activity" in Android. Calling finish() or pressing back on the activity does not remove objects from memory that the activity used. Android inherently takes care of this itself at some random point in the future.
If you want your objects to be released from memory at the moment the activity finishes, you need to manually release them yourself.
Edit: The class that can be used to find memory usage is the ActivityManager.
If it's not yourself who is holding a reference ("references the Activity through a Weak Reference stored at Application scope", do you null it? I wonder why you reference the activity in the service, usually its the other way), did you try to execute a GC? As long as there is enough memory left, no gc will take place to move the trash away.
I'm attempting to learn the ropes of Game Development and Android and it's been a great learning experience so far, but the Android Activity Lifecycle stuff has me a little stuck.
Let's say I have three Activities -
Game Menu
Level Select
The Actual Game (2d Game using the SurfaceView).
I would think I need to load all Bitmaps and Sounds outside the Actual Game Activity to prevent from having to unload and reload them everytime onDestroy and onCreate is called, for example, like when the phone goes to sleep, or everytime a new level is chose from the level select screen.
This led me to the Singleton approach which makes sense and seems to be what I'm after, but I don't fully understand where I would need to unload the Singleton to make sure it gets GC'd, for example, could I release it in the Game Menu onDestroy, if so, how do I know if the Game Menu Activity will hang around indefinately. I've also seen mention of Android being able to kill the singleton on its own. I have also read some about using the Application Context that would give me lifecycle.
What would be the best way to approach this? Do I really want to unload and reload all the resources in the Game Activity? Am I going in the right direction with the Singleton or Application idea?
Always assume your activity will be destroyed. Assuming otherwise will always give you headaches.
Personally I've taken the approach of having my Loading and Main Game activity one in the same in the sense that while the surfaceview is being created I can overlay a loading graphic/screen on top of the surfaceview and preload all the bitmaps/sounds in onCreate.
The level select and other activities are then spawned from the main activity, typically through a startActivityForResult. This allows you to 1) Create a loading screen while preloading/instantiation takes place 2) Present a main screen with Start Game etc... 3) Have the surfaceView already created but being hidden or behind the main game activity.
Obviously you shouldn't be starting threads or anything until they start the game but the surfaceview itself can be ready to go. In that way Start Game is seamless and quick. You just hide all the other Views and bring your SurfaceView to the top.
But again, always assume your activity will be destroyed. Meaning saving game state etc...
With regards to the Main Game you should split your game into 2 threads - one for game logic and one for the actual drawing on the canvas. In your Game Activity you should override:
onCreate: Preload bitmaps, sounds, instantiate main game class and start game thread (UI/Canvas in addition to the game logic thread) when the Start Game button is pressed
onDestroy: Kill all threads
onPause: Pause all threads (canvas thread should be killed on surfaceDestroy)
onResume: resume thread
Always profile your app using the tools available. Have your application update threads and track it using the resource tracker to make sure you aren't using temporary objects. Always create such objects in your main activity/class and reference them. My app never runs GC unless I tell it to and it runs smoothly using the aforementioned design.
Hope this helps. I've written some posts with regards to Android Game development at methodin.tumblr.com.
Activity's onDestroy method is not guaranteed to be called (e.g. Task killer), so don't depend on it.
If you need to presist some class across your application cycle, Singleton or reference them in Application Class is also applicable, indeed, Singleton seems makes more sense to cleaner design.
I don't think you need to explictly remove your stuff, since GC will release everything once it is not needed (at least it will once your application is killed by android). Furthermore, attaching those objects to Game Menu's lifecycle is a bad idea. I guess your activities would like:
Game Menu Activity -> Level Selection Activity -> Main Game Activity
It is sometimes possible that, while you are in "Main Game Activity", the "Game Menu" is actually destroyed. (Yeah and if you press 'back', it will switch to a newly created game menu)
The Application class is a place to store information that will be available for the Application lifecycle. This is a good place to put things that are used by multiple activies (global application state). This is essentially the same as using a singleton.
However, if the user leaves the application by pressing home, there is no guarantee that the Application will live on forever. If they come back 20 minutes later the app may need to get recreated.
I don't think you need to worry about things being GCed, Android will take back memory if it needs it. Otherwise, things will be released when the Application exists.
Make sure that you read the information on the Activity lifecycle closely though. If you go from GameActivity -> Level Select -> GameActivity, most likely the GameActivity will not be destroyed and recreated. Instead, it will just be stopped and restarted. This is not a guarantee, but will be true in most cases.
You shouldn't have to worry about GC yourself. When a user leaves your app (and doesn't return for a while), the OS itself will take care of disposing the app for you.
If you're wanting to use a singleton, you can declare it at the Application level. For example an "AssetManager" is available here:
public class YourGameApplication extends Application {
public AssetManager assetManager = new AssetManager();
#Override
public void onCreate()
{
super.onCreate();
}
}
You can then call it from another activity:
YourGameApplication application = ((YourGameApplication ) this.getApplication());
application.assetManager.someFunction();