How to release memory when activity goes to stack? - android

My application consist (for example) of 3 activity: Activity1, Activity2, Activity3. Every activity has a unique background image on all its main layout declared in an XML File.
From Activity1 user goes to Activity2 and next to Activity3 so first 2 get pushed into the stack.
The problem is that first 2 activities occupy too much memory, and in Activity3 I have OOM exception sometimes.
I have found this answer about reason of this behavior - https://stackoverflow.com/a/4836241/1159507
Before this, I believed that when activity goes to stack it releases all memory.
I believe that the same behavior with fragments stack.
So my question is - how to relese memory when activity or fragment goes to stack and keep responsible UI on back press?

Activity's resources (which are not released in onPause, onStop, ...) do not get released when the Activity goes to the background.
You can remove the background in onPause(), this way the GC will
be able to destroy it. However, the "empty background" will be there
for a fraction of a second. It is important to mention, you have to
do this in onPause(). (I think changes after onPause (like changes in onStop) take effect when the Activity comes to the foreground, so the reference to the background would still be hold by the Activity while it is in the background.)
Other way is to call finish(), and manage the stack yourself. You
would have to remember the starting Activity, and navigate to it
manually when the user presses the back button.
And the last solution that pops into my mind is to make every Activity that contains huge resources a separate process by declaring the android:process attribute in the manifest. This way all of your Activities would have a separate full sized heap to use.

You can save all your huge memory consuming objects (Ex: Large Images in your case) to local storage in onStop() of your first activity and when user presses back you can load them in onStart() of your first activity.

Related

how to save an activity to disk and reload it when restart it

I have an myApp, which first starts ActivityA, then ActivityA start ActivityB. ActivityB is quite complex which holds 3 tabs.
I wrote another killApp to call killbackgroundprocess to kill my app to simulate system out of resource to recycle some apps.
After clicking home button, then running my killApp to kill my app, then start myApp again. I saw a white background panel for a while then ActivityB is repainted.
My understanding is that when clicking home button, myApp's activities are stored to disk, when restart it, ActivityB is on the top of the activity stack, so its onCreate is called again. Because ActivityB requires some time to init its content, so I saw a white background for a while before the whole activity is ready.
My question is:
1. If the app is started first time, there is no such white background issue, is it because during App starts, android system will load all resources into memory, so when ActivityB is created, it doesn't need to wait for resources to be loaded?
2. How to solve the above white background issue? My idea is to save the whole activity to disk, such as serialize the whole activity object to a disk, then when onCreate is called again, de-serialize it. But I am not sure how to implement it. Any suggestions? Thanks.
I suggest reading more on Activities' LifeCycle.
http://developer.android.com/guide/components/activities.html#ImplementingLifecycleCallbacks

Issue with Activity killed by System if No Longer Visible in Android

I have There Activities(A,B,C) within my Application.When i start the Application
Activity A:
A:onCreate()
A:onStart()
A:onResume()
Using intent i am calling Second Activity(A -> B):
A:onPause()
B:onCreate()
B:onStart()
B:onResume()
A:onStop()
Then I click the "Home" button So the App goes to background:Now
B:onPause()
B:onStop()
After 1 or 2 hour later Again i go to home page within my device and Click the App icon it runs like:
B:onDestroy()
A:onRestart()
A:onStart()
A:onResume()
But i need to go which one Activity i quit like this,
B:onRestart()
B:onStart()
B:onResume()
I have read some articles it says like that activity killed by the system because of no longer visible.Is there any possible to fix my issue...
Thanks in advance...
You may be confusing two different things here:
Android does not kill an activity if it needs memory. What it does is that it kills the whole process that the activity is running in. In general that means that Android kills all of your activities in this situation. However, it remembers the activity stack and when the user returns to the application, Android will create a new process and then recreate each activity (in turn, as needed). It starts by recreating the activity that was on the top of the activity stack (ie: where the user left the application).
Android assumes that if the user leaves a task for a long period of time (I think this is something like 30 minutes) then he is no longer interested in that task and there is no point in remembering where the user was in the activity stack of that task because he probably doesn't care anymore. In this case, what happens is that when the user returns to the task (or restarts the application that was on the top of the activity stack in that task) Android simply clears the task back to the root activity. This has the effect that it looks like the application is starting all over again. This is the desired (and documented behaviour).
What you want to do is prevent Android from clearing the task in situarion #2. You do it by adding
android:alwaysRetainTaskState="true"
to the <activity> tag of the root activity (ie: the activity that starts your application, the one with ACTION_MAIN and CATEGORY_LAUNCHER).
I don't believe this is something you can surely control. If your activity is in background for a lot of time and meanwhile other applications need memory, the system will kill your activity to free memory.

does object die navigating between activities?

I have an application that navigates to the same activity but each time the activity loads with different parameters. In my application it's a parsed data content retrieved from url. First thing I want to ask: When I push the backbutton of my device I get my earlier activity without being recreated. Is the objects in this activities alive and can I reference them?
Second question is if my first question doesn't make sense, what do you advice me to do?
If you look at the Activity life cycle, you'll notice that as long as your phone has enough memory, your first activity is kept in memory, and with it any member with the data it contains.
But if your phone needs to have some memory, it can kill any activity kept in background (any activity but the one being shown to the user), which means that you'll loose any data that was in your first activity.
To know which happened, keep in mind that the onResume() method will always be called when your activity is brought to foreground (either on creation, or when you navigate back to it), but onCreate() will be called only when your application is created from scratch (meaning you don't have any saved data).
You should use the bundle mechanism to save data when your activity is paused, and load it when you come back to it. Read the paragraph about Saving Activity state in Android doc to see how to use this.
You are not guaranteed that in memory data will be around once you leave an Activity. Read through this part of the dev guide thoroughly to understand the lifecycle of an Activity: http://developer.android.com/guide/topics/fundamentals/activities.html
If you need to persist information, you should override the onPause, onStop, and/or onDestroy methods of your Activity. You can then save your state using SharedPreferences, the SQLite database, or even a flat file.
In the manifest file add the following to the activity:
android:launchMode="singleTop"
In your example what is happening is when you navigate back to the activity using the back button you are bringing up the activity from the stack. When you navigate to the activity inside of the app what is happening is a NEW activity is being created, while the original is still on the stack. The singleTop launch mode will pop the activity out of the stack if it is there when you navigate to it in the app, and only create a new activity if it is not on the stack.
Without singleTop each time you launch the activity in the app it will create a new instance and you will find there are times you have to hit the back button on the same activity more than once due to multiple instances.

android memory management in activity lifecycle

My question is a little bit complicated.
I want to understand how the app treats resources (especially images for backgrounds, buttons, etc.) when Activity is started, then suspended.
For example, I start Activity A, it shows all the images on the screen, eats its memory, then another Activity B is started and A is suspended. What happens to all the images, resources, etc.? When they are freed? How can I take control over them? Should I not keep the Activity A in the memory and remove it from the Activity stack?
If you need any clarification for my questions, pls write me!
Thanks in advance!
Danail
Activity doesn't free resources until it's finished. But in most cases it mustn't be a problem for you. In my opinion, you shouldn't add your own resource management and make your code complicated in most cases.
But if you really think that your app can be out of memory, you should check it with something like MAT. Problems with memory may be caused by memory leaks, not heavy memory usage.
Eventually, when you're absolutely sure that you have to do something to reduce memory usage, you can do some memory optimization. For example, you can save memory-consuming objects (e.g. large images) to local storage in onStop() and load them in onStart(). I think using onPause()/onResume() for this purpose is a bad idea, because Activity is partially or even fully visible.
In theory, you can even destroy all your widgets in onStop() and restore them in onStart(), but it can make your app too slow. And, of course, in this case state saving must be implemented by you.
Finishing activities may seem to be a good idea, but I think it's not. Firstly it makes your work slower. Secondly you must manage activity stack and state of activities yourself.
For example, Activity A starts Activity B. So, Activity B must know what to do when user presses Back button. When user presses back button you should start Activity A and restore its state. But what if user terminates this app. In this case you must initialize Activity A with its default state. So, you have to implement a lot of additional logic.
In conclusion I'll repeat the main idea one more time: don't optimize memory usage if you aren't absolutely sure you have to!
Okay so we have the following situation:
A > onCreate
A > onStart
A > onResume
A > Use up a load of memory (A could even use up too much and crash)
A > Launch activity B
B > onCreate
A > onPause
B > onStart
A > onStop
B > onResume
B > Use up a load of memory
If B uses up enough memory then the Android system will kill activity A (you'll notice the onPause and onStop methods of A have already been called so it's already been given a chance to save it's state)
If you then press the back button the Android system will just start activity A again (and if it's clever it should remember it's last state) so it looks like nothing ever happened to the user.
So to be a bit clearer: if you start B and then finish A, B will essentially just replace A in the activity stack and pressing the Back button in activity B will just exit your and app and not return to activity A.
If on the other hand you start B without finishing A, then pressing the back button in B will take you back to A. While activity A is in the background it could be killed to reclaim memory, but Android will recreate it as needed when the user navigates through the activities stack.
Also if you have in memory-caches of multiple objects (e.g. bitmaps/drawables) then back your collection by SoftReferences so that the GC can clear them up if it's running low on memory.
You should design your app so that it's memory usage is low, but you can count on the framework do it's best in memory management. So, do not work too hard with removing unused stuff, only in cases when it's obvious that your app is eating too much memory.
When the available memory goes down, the framework will stop and remove activities and services which are not associated with the current task. If your app eats up even more memory, the framework will stop your activities which are in the background. Then comes the services associated with your app and the last one to finish off will be the current activity.
When the framework stops an activity it does keep record of the activity stack, the intents used for starting the activity and the bundle returned by onSaveInstanceState(), so it can recreate the last known state of the activities. Also, the framework can unload unused resources (drawables, etc.) when not in use and reload them when needed.
Well before replying to your questions, I have certain facts to discuss.
As per the life cycle of the Activity, if we call finish() then the onStop() called and finally the onDestroy() which eligibles that Activity for Garbage Collection and remove from the Activity Stack of Android.
Android is maintaining the Drawable cache for the Activity designing and displaying on the screen. So if you disable the drawable cache on the Activity onCreate().
So the best practice is to disable drawable cache on the onCreate like this:
LinearLayout v = (LinearLayout) findViewById(R.id.mainLayout);
v.setDrawingCacheEnabled(false);
and to call finish(); on the onPause();
You have very little control over memory when you writing Java code. This is a good thing for most of the cases. Actually most of the application do not need to worry about memory.
To answer your question, all the object for activity A will still be in memory when it is suspended. VM will start GC when it needs resource.

How to limit the number of the same Activity on the stack for an Android application

Is this possible in an Android app? I want to make it so that no matter how many times a user starts activityA, when they hit the back button they will never get more than one occurence of activityA.
What I am finding in my current code is that I have only two options:
1. I can call finish() in activityA which will prevent it from being accessible via the back button completely, or
2. I do not call finish(), and then if the user starts activityA (n) times during their usage, there will be (n) instances when hitting the back button.
Again, I want to have activityA accessible by hitting the back button, but there is no reason to keep multiple instances of the same activity on the stack. Is there a way to limit the number of instances of an activity in the queue to only 1?
One option is to use Intent.FLAG_ACTIVITY_REORDER_TO_FRONT every time you launch an Activity so that if an instance exists it is brought to the front of the stack and not created every time.
This way you are ensured that only one Activity will remain on stack.
You might want to set your activity as singleTop -- this basically means that you can have multiple instances, but the app will reuse an instance if you try to launch an instance on top of itself. See the Android documentation on Activities and Tasks.

Categories

Resources