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.
Related
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.
I have 2 activities. Main Activity A & Activity B
I do not want Activity A to destroy. I am starting Activity B in a new task.
public static void startActivity(Class<?> startClass) {
Intent intent = new Intent(Constants.getActivity(), startClass);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Constants.getActivity().startActivity(intent);
}`
Constants.getActivity() returns the Context on current activity
startClass is the either activity "A" or activity "B"
Thing is they create/destroy the activities and they leak. Am I doing it wrong? How can I start activity "B" from activity "A" and vice versa keep them both in background when I dont need them.
First of all, what are you trying to do? You should always separate things you want to do in the background from your UI. Think of your Activities are simply a container to show the UI, everything else can be stored and restored from persistent storage or savedinstance bundles.
It is very crucial that you understand the difference between Activity lifecycle and Service lifecycle here.
I'm going to refer to my answer from another question here:
Your app will be in the background, onResume and onPause will both be called, provided that the OS have enough memory to keep the new app and all the old apps.
If you have a long running process that you need while the user not looking at it, use a service.
If you need the user to return the app in the same state, you need to do the work in onResume and onPause to save the state information and initialize your UI again when the user comes back. If you are really worried that it can get killed (well, it shouldn't lose the bundle I think), you can store them in SharePreferences for your app.
If you want to know when the app returns from that specific share intent, use startActivityForResult
You cannot keep an activity "alive" as you said. When an activity is paused, Android system is always able to claim its memory and unload it, at any time.
But if you want to switch from A to B, then maybe A and B can be different views inside a single activity. Maybe you'll want to have a look at http://developer.android.com/reference/android/widget/ViewFlipper.html
When you use tasks, cleanup is very important. You need to cleanup all tasks in the activity. readthis
If the activity does not have a lot of crazy initialization, just use finish and onCreates. Else be aware that onResume will be called often as you switch between activity's. Cleanup will be crucial here. If you dont cleanup, its possible one of your activities (with dead object reference from the other cleaned up activity) may come back up from the activity stack and throw exceptions. Its very difficult to debug this kinda exception.
My application has several components including a ListActivity and a MapActivity. I'm running into a weird problem where parts of those activities seem to be deallocated after resuming my application from background.
It's fairly deterministic. I'll return home from my application, then run other application/go on browser and then return to my application. Then my MapView disappears and other components are gone or distorted. Anyone run into something like this?
Memory is taken back by the system if it goes onPause() and the memory is needed by other Apps (Garbage collection). You need to put setContentView of your activities in your onResume() method overload if you need it to resume the old status. Check the activity life cycle
I have activity A, which launches activity B via an intent. Activity A has no references to Activity B, there are also no references to Activity B in the Application singleton I am using.
When I create Activity B, several thousand objects are created. That's okay, it's an activity with a very populated ListView with lots of images.
But, when I press the back button and return to Activity A, only about a dozen of the several thousand objects are released. onDestroy() is also called for the activity. I'm using DDMS to view the heap info, and am pressing 'Cause GC' several times to force it to free memory.
I've done the same test on other apps (that use list views too) and 100% of their objects are destroyed on pressing the back button then 'Cause GC', so it's certainly not a bug.
Any advice please? :-) I've read the material in the android docs about leaking contexts, but that's not helpful since i'm not referencing the activity (or anything in it) being destroyed elsewhere. Also, I have many other activities which work the same way, and don't release all memory on destroy. I must be missing something obvious?
Edit: I just realized i'm using AsyncTasks which have references to the activity (either passed as arg into doInBackground() or accessible via outerClass.this. Could they be hanging around in the thread pool, even after onPostExecute() ?
Edit: It leaks even if I go back before running any asynctasks :-(
Edit: No leak before running asynctasks if I remove admob code, but still leaks in the activites which do use asynctasks.. so asynctask is still a good candidate :-)
I believe there's a bug in the ListView implementation. Take a look at this question: Android: AlertDialog causes a memory leak.
Here's a bug report: http://code.google.com/p/android/issues/detail?id=12334. It's declined but in my opinion it must be reopened.
I create an instance from activity A to B, then in activity B I create another instance of activity A (I want to keep the previous A in history). I keep creating instance and I have a history stack from Activity A -> B -> A -> B -> A.....and after like 20 times, the system looks like need more memory and will kill the first activity A, then B (it calls onDestroy() from Log)...each at a time when I create each activity. I never have any memory issue in this scenario. But if I suddenly create an activity C which has lots of images that requires large memory, it will throw an Out of Memory Error: VM wont let us to allocate 70k bytes something like that.
So anyone know when will system kill an activity? Does it kill only 1 activity each time? How can I let the system give me more memory before I start activity C? Do I have a memory leak on this? Any help is appreciated.
Android does not kill activities unless memory is demanded. They simply remain in memory, paused. If you are switching from Activity A to B and back, Android is simply changing which is visible and onResume()d - they are not being killed (to read more on this search on Android Activity Stack). A memory error on activity C probably is entirely an issue within C. Depending on your situation, it may be easy to change the AndroidManifest just to test launching C directly... you're likely to get the same result. FYI.. call finish() to exit an Activity manually and free resources.