In my app, I have two activities. Let's call them A and B:
A can launch another A activity or launch B
B can launch A activities only
With this workflow, it's possible to open a long stream of A and B activities. It's even possible to open the same set of data recursively (and therefore keep going until the app crashes).
Sometime in the future, I'll probably implement "singleTask" launchMode with my own activity history.
But for now, what I'd like to do is keep the back stack, but release memory for activities that are not in the foreground (ideally maintaining one active instance per Activity).
I thought that clearTaskOnLaunch would do this for me, but my memory footprint gradually increases as I open one activity after the other. Is this expected behaviour, or does this indicate that I have a memory leak?
Tasks and Back Stack or link this may help you
Related
I wrote a small game on android. It has one activity + one fragment. I save the state of the game in Fragment.onSaveInstanceState and restore the state in Fragment.onCreateView.
If I rotate the screen, the game state is preserved properly. However, if I turn off the screen and come back to the game at a later time, sometimes I lose the game state and get a new game instead. Therefore, I wonder if Fragment.onSaveInstanceState is called at all when the system decides to kill a process to recover memory. Also, what is the life time of the stuff that gets saved into the Bundle in Fragment.onSaveInstanceState?
By the way, is there anyway to easily test such a case during development? It'd be terribly inefficient to wait for a day or two for the system to kill it.
Thanks for helping me out!
I wonder if Fragment.onSaveInstanceState is called at all when the system decides to kill a process
Yes.It is called.
I think your issue lies somewhere here.From the documents :
The most significant difference in lifecycle between an activity and a
fragment is how one is stored in its respective back stack. An
activity is placed into a back stack of activities that's managed by
the system when it's stopped, by default (so that the user can
navigate back to it with the Back button, as discussed in Tasks and
Back Stack). However, a fragment is placed into a back stack managed
by the host activity only when you explicitly request that the
instance be saved by calling addToBackStack() during a transaction
that removes the fragment.
Not sure if this can solve your problem but i think you should keep it in mind while writing your game code.
There's a scenario in my app which it could go activity a->activity b->activity a->activity b...infinitely, and eventually it'll get OOM.
Is anybody aware of a way to make it like the "don't keep activities" behaviour,e.g. the activities will be killed to release memory but still in history, so it can be recreated as user navigates back?
This isn't possible. The activities need to be present in the stack for Android to be able to go back to them. What you can do is to keep track of the data that the activities are managing yourself, so that as the user goes from ActivityA to ActivityB to ActivityA you keep pushing a data packet onto a stack that is available to both activities. Then you can use `Intent.FLAG_ACTIVITY_REORDER_TO_FRONT' to transition from one activity to the next.
In this case you will only ever have one instance of ActivityA and one instance of ActivityB, but they should be able to present the user a different view each time they get control by just looking at the data packet on the top of the stack. When the user presses the back button, you should pop the top data packet off the stack and then start the appropriate activity for it (using `Intent.FLAG_ACTIVITY_REORDER_TO_FRONT' to ensure that you don't create a new instance).
First of all, I'm new in android developing...
I had read some article in android API guide and feel confused about the component life cycle with the hosting process.
Here is my understanding:
Android system may kill some activities in a process or the whole process in low memory situations,which means there is a possibility that a started activity may die, but process still alive.
If a service is started and not call any stop method, when in extreme low memory, this service is killed by system with its hosting process, not just the service itself, means this circumstance should not occur:service is killed by system, but hosting process still alive.
When an app starts, the user navigates activity1 -> activity2 -> activity3 and none of them call finish(). Next, the user navigates to another app's activity and plays with it so long that the former app process is killed by the system. Now the user navigate back to activity3 in the back-tracking stack, what will happens? The former app process restarts with only activity3 recreate?
Anything wrong ?
There is no need to switch to another app's activity: from the moment that you leave the first activity to go to the second activity; there is a clear possibility that the first activity might have been destroyed when you return on it from the second activity (back-tracking) and when you go to a third one, either the first one, the second or both of them can be possibly destroyed in the mean time. In fact, you don't even to leave an activity to see it destroyed; as this will automatically happen simply if you switch from the portrait mode to the landscape mode and vice-versa by rotating the device.
When you return to an activity, the onRestart() function will be called if the activity has not been destroyed in the mean time. If it has, the "onCreate(Bundle savedInstanceState)" will be called instead but with the argument "savedInstanceState" set to a non-null value (ie, it will point toward a valid Bundle object) if you have took the precaution of saving the current state of the activity in the "onSaveInstanteState(Bundle outState)" function when the activity has entered the process of being destroyed by the system. The system will always call this function before destroying an activity when this one need to be restored later for back-tracking. Of course, it won't be called after a call to finish() because this will also remove the activity from the back-tracking stack.
Finally, in Android, the coupling between activities in the same application is very loose. When it comes to the use of resources, there is not much of a difference between switching to an activity from the same application or from another application. In many ways, activities will behave like if there were all fully independant applications when it comes to running. This is why you always need to use an intent to start an activity; even when it is from the same application.
Based on my understanding ...
In android during low memory situations, first activities would be removed from memory where the onDestroy method gets called.
This is not the case always. It depends on how the service is started i.e whether from onStart or through Binding the service with a component.
Once the former app process is killed, then when the user launches the application, he will be taken to activity 1. Launching the activity in same task or different task depends on launch modes used (single task, etc)
Thanks for reading by question, albeit a really noob-ish one...
How does the Android system manage memory with regards to activity initialization, specifically if an activity is initialized through other activities? This has been a lingering question in my mind for a while, but I'll try to illustrate with an example:
Say I have 3 activities - A, B and C - with activity A being the one that is launched when the application is started for the very first time. Now, let's say activity A has buttons to navigate to activities B and C, and those activities are launched using Android's startActivity() function, passing it an Intent instance. Similarly, let's say activities B and C have buttons to launch their counterpart activities...make sense so far?
Now, if I then use the startActivity() to:
start activity B from activity A
then start activity C from activity B
then start activity A from activity C
then repeat the above steps indefinitely (so going around in circles)
...would it be fair to assume that the Android system would "know" that the activities had already been started previously and wouldn't re-initialize them and kill more and more memory, but rather call something like the onRestart() functionality to rather "switch" back to an already initialized instance of the activity?
Quite an explanation for a really simple question / problem...apologies if this has already been asked and answered somewhere else...I couldn't find a clear answer anywhere else, even while reading through the Android training section on the Android developers site.
The answer is: It depends. :-)
If you use the standard settings for the activities A, B and C, your application will run out of memory. The reason is that Android will keep each activity in the "Back Stack" that allows the user to navigate back by pushing the back button.
However, if you set the android:launchMode of your activities to singleTop in the AndroidManifest.xml file then Android will route the intents to the running instances of the activities by invoking onNewIntent() in the activity.
You can read more about it in the Android Developer Documentation regarding launch modes.
I'm launching an activity (ActivityA) using the technique described here with FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP. This works if all of the activities on the back stack are still in memory. ActivityA is shown and if I tap back, the app exits.
If I use SetAlwaysFinish to make paused activities be immediately finished and repeat my test, then when I tap back in ActivityA, I'm taken to the previous activity. This shouldn't happen.
Am I testing realistic conditions when I use SetAlwaysFinish? If so, how do I configure and launch ActivityA so that the back stack is really cleared and my test works under both conditions.
Using "set always finish activities" does not simulate any realistic condition. It is supposed to be used as a debugging help, but since Android doesn't actually finish activities when it needs to recover resources (it actually kills the host process instead), it is little help in debugging or testing real world conditions.