Fragment not clear on memory heap after destroyed - android

In my app i use backstack for my fragment and popBackStack to back previous fragment.
I have problem when i back to previous fragment by popBackStack. (FragmentA->FragmentB->FragmentA). I see that in fragmentB when popBackStack to previous fragmentA, It's called onDestroy method. I find FragmentB in getFragmentManager().getFragments() but I can found it.
However, When i dump memory heap, I find x FragmentB on heap (i open fragment B x times). It increase my memory heap and then I got error OutOFMemory when I repeat flows A->B->A until full heap.
I cannot find any solution or cause of my problem. Is there any suggestion for my problem?

1> Try to maintain the fragment in the stack (add a popup while you are adding the new fragment)
For Example:
private Stack<Fragment> fragmentStack = new Stack<Fragment>();
// code to add new fragment in stack and previous fragment in back stack
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment mFragment = new Fragment(); // you can replace this with your fragment
ft.add(R.id.container, mFragment); // you can also add fragment id so that if you can reuse that fragment if it is memory.
fragmentStack.lastElement().onPause();
ft.hide(fragmentStack.lastElement());
fragmentStack.push(resultListFragment);
ft.commit();
// code to remove visible fragment from top and resume back stack fragment
if (fragmentStack.size() == 2)// used to check whether their is any fragment in stack is yes than go for back event like onbackbutton event {
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentStack.lastElement().onPause();
ft.remove(fragmentStack.pop());
fragmentStack.lastElement().onResume();
ft.show(fragmentStack.lastElement());
ft.commit();
}
2> If the above code snippet doesn't solve your problem for OutOFMemory error, then use setRetaininstance(true) in onCreate(Bundle) system callback method of the fragment lifecycle so it will not create a new fragment if its already the in memory.

Related

Get fragment from backstack

Hardly can't get fragment from backstack, even start thinking of keeping in in singleton which is probably bad.
Saved to backstack like this and all time try to get it by tag or something gives me error.
Fragment fragment = UserProfileFragment.newInstance(null);
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(FRAGMENT_PLACE_RESOURCES, fragment);
trans.addToBackStack("profile");
trans.commit();
It just return me null here so I can't use this fragment. No logs.
Fragment fragment2 = getFragmentManager().findFragmentByTag("profile");
getFragmentManager().findFragmentByTag("tag")
is only used when you have added a fragment with specific tag for e.g.
fragmentTransaction.add(R.id.order_container,mProfileFragment,"profile");
or
fragmentTransaction.replace(R.id.order_container,mProfileFragment,"sometag");
Then you will be able to find this fragment by the tag.
In your case you are adding a transaction to backstack so you will not be able to find that fragment by tag. You just adding a transaction to backstack thats it not a fragment. And also your fragment was removed from the activity and destroyed so you have to revert the transaction by popping backstack instead of finding that fragment by tag.
You have to call
getFragmentManager().popBackStack("profile");
to get that fragment back to the activity and make it visible on screen.

Fragment with MapView is never removed from FragmentManager

I have a Fragment with MapView in it. I add Fragment to container with following code:
Fragment fragment = new MyLocationFragment()
String tag= fragment.getClass().getName();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
transaction.replace(R.id.container, fragment, tag);
transaction.addToBackStack(null);
transaction.commit();
Now when user presses back, this Fragment is supposed to be removed from FragmentManager. But if execute this code :
Fragment fragment = getSupportFragmentManager().findFragmentByTag(MyLocationFragment.class.getName());
It never returns null, even if I replace other fragments in same container. What can I do to remove Fragment from FragmentManager? Am I doing something wrong here ?
When an activity is destroyed, its FragmentManagersaves out its list of fragments. When the activity is recreated, the new FragmentManager retrieves the list and recreates the listed fragments to make everything as it was before.
[Refer to book "Android Programming The Big Nerd Ranch Guide" P150]
So your should remove fragment from fragmentmanager.
Refer to this Q&A Remove old Fragment from fragment manager
Your question maybe duplicate with thisHow to get a Fragment to remove itself, i.e. its equivalent of finish()?

Android - How to resume fragment from back stack if it exist?

Hello I am working with sliding menu with fragment.
Indivisual fragment works properly. But suppose user navigates From fragment A->B , now 'B' works perfect and now if user goes from B->A than fragment 'A' is called from onAttach() .
I want such a condition if any fragment is opened , than reopening it should not load whole fragment , it should be resumed just like we handle activity with Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
Here is my code...
FragmentManager fm = MainActivity.this.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Layout1 fragment = new Layout1();
ft.add(R.id.activity_main_content_fragment, fragment,Layout1.class.getName());
ft.addToBackStack(Layout1.class.getName());
ft.commit();
Answer updated:
Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.
Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.
So if you want to store state you should use instance variables and not rely on onSaveInstanceState()
Check this link. it will help How to resume Fragment from BackStack if exists

Detail fragment over listing fragment

I have two fragments - Listing and detail. Initially I load the listing fragment in the container of the activity using
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, listingFrag);
ft.commit();
On tapping an item in the listing fragment I load the detail fragment using
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, detailFrag);
ft.addToBackStack(null);
ft.commit();
On loading detail fragment I do not get the onPause call of the listing fragment. Neither do I get the onResume call of the listing fragment on coming back from detail fragment (using the system back button).
Also, when I am in the detail fragment, putting the app to background calls the onPause of both the listing and detail fragments. On getting back the app from background, onResume of both listing and detail screens get called.
The above mentioned behaviors are quite unexpected.
I would want
1) listing fragment's onResume to be called on coming back from listing screen
2) listing fragment's onPause to be called on loading detail fragment
3) only detail fragment's onPause to be called when the app is put to background
4) only detail fragment's onResume to be called when the app is brought back from background
Can some one please explain a way to do this.
Thanks in advance!
onPause and onResume in fragment are just the reflection of onPause and onResume in Activity.
So every time you go from one activity to another all the fragments of the first activity will call onPause and all the fragments of the 2nd activity will call onResume.
This functions are not for fragment visible/add or remove.
When you display the detailed fragment, you add it which means that both the listing and the detailed fragments are active at the same time. Hence both of them receive onPause() and onResume().
You should instead try replacing the listing fragment with the details fragment. That will cause onPause() in the listing fragment and only one fragment will be active at a time.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, listingFrag);
ft.addToBackStack(null);
ft.commit();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, detailFrag);
ft.addToBackStack(null);
ft.commit();

Cleaning fragment

Is there any way to clean up fragments' state?
I mean such situation:
I create a fragment instance (lets call it A) passing it an ID to load some content, than return to previous fragment (B for example). And when I go to A again, passing NO ID (it should than load default data) - it already has an ID from previous usage and my logic breakes.
Do not add your 'A' to backstack. So it will not be saved into backstack. Whenever you go back and come again it will not be added. Is this what you want right.
// Instantiate a new fragment.
Fragment newFragment = CountingFragment.newInstance(mStackLevel);
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//ft.addToBackStack(null);// Do not add to backstack here.(add every time new).
ft.commit();

Categories

Resources