Android fragments and memory - android

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.

Related

Should I replace Android Activities by Fragments?

I have a large Android game in which there is an Activity for each logical screen.
(Splash screen, start screen, level chooser, game screen and Settings are distinct Activities).
Everything is working fine right now.
If I rewrite everything so that there is only one activity and the logical screens are Fragments, Will it reduce RAM or CPU consumption?
After years (two+) of saying "Fragments are the way to go", I would never replace activities with Fragments again.
Using fragments to rehuse certain components is fine. Using fragments for dialogs is also fine, but I have now realized how awful the Fragment implementation is, how awful the Fragment lifecycle is and how unpredictable (and buggy) FragmentManager tends to be under certain circumstances. Go ahead an spend some time googling around and you will find all the "edge but not so edge" cases where hacks have to be implemented to work around a "by design" buggy behavior.
Sometimes you have to extend or copy the source code of these classes from the Android Source Code to modify a private or protected field…
Don't get me wrong, Fragments work. But they are not the solution to all your problems (they are possibly the source of new ones in the mid-long term). If you already have Activities, enjoy that! In fact, the new Transition Frameworks with Shared Elements is a clear indication that Google wants you to use more activities ;)
This is my personal opinion after working in roughly six mid-large sized Android projects (some are popular and you've probably used them!) ;)
As far as I know, no, Fragments have (near to) no impact on RAM or CPU.
An Activity contains certain elements and performs some functionality. A Fragment is loaded onto an sort of base Activity, like an Activity with no more than an ActionBar. The rest is filled by the Fragment.
Also check out:
android - need some clarifications of fragments vs activities and views
Activity or Fragment which is better way to use for performance and reliable?
No, it will probably increase it (as you will have more classes) but only marginally.
The benefit of using fragments is to have reusable "blocks" that you can move around depending on your needs. For example for a specific activity you could have a layout where you have your main window on screen and clicking on an item creates an new activity with some details. With fragments, you could create a layout for tablets where the main window takes only half the screen and the rest is used for the details fragment, witout having to rewrite everything.
The main benefit of fragments to me is easy data sharing. Between two activities, data has to be passed in relatively primitive types...string, int, arrayList, etc.
However between fragment and activity, data can passed back and forth in complex classes.

crash on dynamic creating views fragment onresume android Galaxy Tab GT-P3100

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.

Memory Leak on Orientation Change

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"

Memory issues with a large number of fragments in back stack

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.

Full managing of fragments flow in Android

I have a special flow of fragments in my app, so I need to be able to switch to any fragment, while keeping fragments in memory whenever possible (so if it's tight on memory, it's ok that the fragment will be released).
So far, I've succeeded doing a replace of the current fragment, but the thing is that the previous fragment is always being destroyed, so if I go back to it (using the action bar, for example), it's re-created and that takes some time.
The reason I use fragments instead of activities is the nice usage of the action bar, the ability to put multiple fragments inside the same container, the non-flexible activities-intents usage, etc...
The reason why I don't use the "Back" stack is that I wish to go to any fragment from any fragment, since the flow can change.
Here's a snippet of my code:
Fragment fragment=... ; //get the fragment from cache or create if not available yet...
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.mainActivity_fragmentContainer, fragment).commit();
I have also tried to use ViewPager, but since I don't want to have the sliding effect (which allows you to slide to other fragments) and since one of the fragments already include a viewPager, it's an obstacle. Disabling the sliding effect on the main viewPager somehow disables it on the other one.
BTW, I'm using the android support library for the fragments and not the native API.
my question is:
how can i achieve full control of which fragment to go to , while maximizing speed and avoiding too much memory being used for fragments ?
EDIT:
for now , i use the next workaround :
for the onDestroyView , i take the parent of the created view and remove the created view from there .
for the onCreateView , if i already have the created view from before , i return it .
however , i think it's a very risky thing to do , since i'm not sure of how fragments managing work , so it might cause weird problems . plus ,i'm not sure what will happen if android decides that it has low memory - will it destroy unused fragments (which is good) or will it cause out-of-memory exceptions (which is bad) .
I agree with your comment regarding "it's very risky". Since the consequences of your approach are not really clear, I would not recommend using this.
To better understand your issue and to give you some indications:
what do you consider to be slow? I keep switching fragments "like crazy" too, and it works OK on a tablet, however on some low-end phones it takes much longer - but is still acceptable
How much work do your fragments need to be created? ie what kind of underlying data needs to be preapared each time? (again, I have several list fragments with more than 1k entries, they get prepared each time, and it's quite fast)
how do you exaclty replace fragments? In particular do you call getFragmentManager().executePendingTransactions();
One way to accomplish your goal is to use FragmentTransaction.show and FragmentTransaction.hide. You can use Fragment.isAdded to determine whether to show or to call FragmentTranscation.add the first time. The downside is that you won't get Pause/Resume events when fragments are shown and hidden; you will need to override onHiddenChanged. You will also have to manage your own stack if you want to support back navigation.

Categories

Resources