I have an activity where the user can progress from one fragment to another. The fragment starts, downloads some data and displays it (along with drawing some icons from resources, etc). The user can continue moving forward through fragments for as long as they like (until they get bored?).
The problem is, an OutOfMemoryError will eventually happen (after around 90 fragments on a 32mb vm heap). 90 does seem like quite a lot, but I have seen such memory error reports in the field, so probably this happens earlier on lower-end devices.
I have made sure any views I create in onCreateView I nullify in onDestroyView. The only other objects my fragments hold (as far as I can tell) are the data it downloads at the start, usually only 10-50kb.
My first question is, is this normal? Can I expect to 'only' be able to have ~90 fragments in the back stack? Or do I have a memory leak somewhere that I can do something about?
If the user goes away from my app, and Android decides to kill the whole process to free memory, when the user returns the memory used is much less because the whole state has been restored from bundles. If the user then back-presss through the back stack, each fragment is then of course created/resumed from savedinstancestate.
So my second question is, is there a way to force this to occur? Ie, 'if there are >50 fragments in the back stack, start killing the ones at the bottom to savedInstanceState?'
All back stack Fragment are kept in memory with hard references. So if you are keeping a ridiculous amount of Fragments in back stack then you will get out of memory.
Have a look here: When a Fragment is replaced and put in the back stack (or removed) does it stay in memory?
Try this in your AndroidManifest.xml in <Application> tag:
android:largeHeap="true"
and provide your code to help more.
Related
My applications memory consumption seems rather high when switching between activities. I quick explanation is that I have an ActivityA that is singleTop and is basically the home screen, you select an item in a list and it takes you to ActivityB which is a more detailed version of the list item. You then press back and it finishes the activity returning to ActivityA. Both activities are quite rich in controls and have high quality images scattered around, but there's definitely something not right here.
I have drawn a quick diagram to show the lifecycle:
As you can see when the app first starts it is at 34MB, after selecting a list item it goes up 2.5MB, then when I press back it goes up again.. this will continue to happen whilst going back and forth. The first thing I need to establish is whether or not this is normal behavior for an application? If this is not the case I clearly have some work to do in releasing some resources, the issue is, what?
In my onDestroy() of ActivityB I unregister from all my receivers, I call finish() on anything I use and have even tried setting everything to null but still no change! I use no special flags when starting ActivityB or finishing it, could that be part of the problem? The history of the stack is sticking around maybe?
EDIT:
I use SceneTransitionAnimation to move an image between the two activities, when I turn this off it goes up 0.5MB each time I go from A to B and 0.01MB when I go from B to A. I guess I should ask the question of how the much bigger increase can be avoided whilst still using SceneTransitionAnimations??
How to switch between screens?
I looked and attempted the above code, and while it does work, it's not what I'm looking for.
In the above example, you open one intent, and then close it when you're done with it. Another example from above showed that I could create new intents endlessly, but then clicking on the Back button of the Android Device makes me go back once for each new intent created, implying that it's going to eat up memory this way.
What I would like to attempt to do is to move between instances of Intents. There will be times when the screens could allow for an endless, memory eating circle of moving between screens.
For example, Screen1 has a button leading to Screen2. Screen2 can lead back to Screen1, or to Screen3. Screen3 can then go back, or go straight back to Screen1. Is there any way to avoid the memory leak for a large number of screens/screen changing/drilling down(Screen1 eventually leading to Screen12 or something)?
In your situation, i suggest you to use a ViewPager to navigate/switch between your Screens.
Just create a Fragment for each Screen (or recycle an old fragment, it depends on what your screens looks like).
I am starting a new app which will include the usage of a lot of fragments.
I started building it, but there is something that bother me...
I made a very simple sample to illustrate what I want to do :
https://github.com/Kobatsu/fragmentstests
There is a button in the action bar to change the main fragment. Each fragment contains only a TextView with a sample text.
It's working, but everytime I click on the button to change the fragment displayed, the memory used by my app (I'm seeing it in AndroidStudio) increase.
It doesn't increase a lot since there is nearly nothing in each fragment, but in my real app it increase more and if I swap a lot between the fragments, I can get an OutOfMemoryException.
Is there something I need to do to remove the fragments from memory ?
I've read your code in github, it seems fine in memory aspect.
If your fragment's onDestory() or onDestroyView() is invoked successfully, usually you don't need to worry about memory.
It's true that Fragment creation will cost memory, but when your memory usage increase to a certain limit, garbage collection or GC will check unused heap objects and free them.
Be careful when other objects potentially hold the fragment instance: like register listener to other thread, or addToBackStack that keeps fragment in stack.
I just want to ask why my app crashes with the following conditions.
I am working with fragments with only one activity. In my fragment, say FragmentA, I create views dynamically (inflating them). They work fine. But when I press home button, and go to the app again, I expect that FragmentA will be displayed but unfortunately, it throws NullPointer.
There is no errors in my android phone[GingerBread] but on my Tab, this error happens. Any help will be higly appreciated. Thanks.
You are not providing enough information to reliably answer this question, but the difference your're seeing is probably related to different behaviour of the garbage collector on the two different devices. As they are running on two different devices they will also behave differently.
The null-pointer you are seeing I would guess stems from wrongful use of member variables in your fragment.
When you go to the home screen and back your fragment will (or more accurately CAN) be recreated. Read: destroyed and re-instantiated using the argument-less constructor.
So make sure your fragment(s) are properly saving any needed state in onSaveInstanceState and restore this information in OnCreate/OnCreateView or whatever you're using.
I've written a pretty standard Android app that displays a bunch of pictures (from Contacts) in a GridView. The app doesn't do anything special to try to retain data on screen orientation changes, and just recreates the GridView, adapter and loader when the Activity is recreated.
However, after a few orientation changes, the app slows down; after a few more, it crashes with an out-of-memory error (at BitmapFactory.decodeStream()). This still happens if I leave it sit for a minute between rotations to let the garbage collector do its thing.
I was under the impression that Android would free all memory associated with an Activity when the Acitivty is destroyed during orientation changes. However, this seems not to be the case. My question is: what memory could I be inadvertently retaining despite Activity destruction?
(Note that the app runs fine so long as it is not subjected to too many orientation changes, so the general approaches to memory minimisation that I'm using are sufficient.)
I think you forgot add bitmap.recycle();
Also easy method fix this, add to AndroidManifest, activity parameter: android:configChanges="orientation|screenSize"