Retain same instance of Fragment on configuration Change - android

I have the following issue. My application has 2 fragments, the first one that is executed show a list of items, when you tap on an item, shows a detail fragment.
I also have a NavigationDrawerActivity, with the following methods to handle the stack of fragments.
private void changeFragment(int pos, Fragment fragment, boolean addToBackStack) {
Fragment f = getSupportFragmentManager().findFragmentByTag(String.valueOf(pos));
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
mCacheServices.setmFragmentTag(String.valueOf(pos));
ft.replace(R.id.container, fragment, String.valueOf(pos));
if ((addToBackStack)) {
ft.addToBackStack(STACK_KEY);
}
ft.commit();
}
The problem i am facing is when i am in the DetailFragment, and i rotete the device, it goes to the ItemList fragment, which is the firs fragment excuted by the app. What can i do to mantain on the DetailFragment when i rotate the device?
Thanks!

you can save the state of the fragment and then re-create it. Go through this for more details
http://developer.android.com/guide/topics/resources/runtime-changes.html
hope this helps.

Related

Android FragmentManager calls onCreateView while clearing fragments

I have these methods for fragment manipulation:
public void replaceFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_frame, fragment);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
}
public void addFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_frame, fragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(fragment.getClass().getName());
}
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
}
public void clearFragments() {
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry first = fragmentManager.getBackStackEntryAt(0);
fragmentManager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Scenario:
I start with fragment A, when activity is created. addFragment(new A, false);
Then I add fragment B. replaceFragment(new B);
I add another fragment C. addFragment(new C);
In C fragment I want to reset application to A fragment. I call clearFragments(); addFragment(new A, false);
The problem is that B fragment onCreateView is called after pressing button on C fragment that clears fragments and adds A fragment. I don't see the fragment, but it starts background thread that crashes my app. I need to clear all fragments without calling their onCreateView() methods.
Is this expected behaviour, or am I doing something wrong?
Actually in such a scenario you will always return to the fragment B.
Step by step:
Adding A.
Replacing A with B <- after this step you don't have A within your activity.
Adding C. Here you are adding another fragment and telling FragmentManager to preserve current state of fragments to the back stack. Your current state at this point is fragment B. Then fragment C is added.
When you call clearFragments, FragmentManager returns to the first saved state - and this state is fragment B.
Maybe you forgot to mention something? I tried to put several entries in a back stack and then reset to the first state - onCreateView is called once, only for the first fragment.

getFragmentManager().popbackstack() causing nullpointer exception

I am developing an android app with lots of fragments in it. But I am facing problems in switching between them.
Lets say I have a Fragment A now I want to go to Fragment B, for this I am doing like this--
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager
.beginTransaction();
Fragment fragment = new Fragment_B();
transaction.add(R.id.frameLayout, fragment);
transaction.addToBackStack(null);
transaction.commit();
I reach Fragment B successfully. Now I have to go to Fragment C from here, for this again I am doing the same thing.
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager
.beginTransaction();
Fragment fragment = new Fragment_C();
transaction.add(R.id.frameLayot, fragment);
transaction.addToBackStack(null);
transaction.commit();
I do this successfully also. Now I have to revert back to Fragment B, for this I do -
getFragmentManager.popbackstack();
This brings me back to Fragment B. But when I do the same to go to Fragment A now, it causes NullpointerException.
What I am doing wrong here. Why does this run perfectly for the first time but fails at the second time? Please help.
I think you have to check first there are fragment available in backstack or not. follow my below code:
if(manager.getBackStackEntryCount()>0){
manager.popBackStack();
manager.beginTransaction().commit();
}
Thats it...
and yes you do not add fragment a to backstack initally so crosscheck that..
fragmentTransaction.addToBackStack("tag");
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}

List view reload when back pressed in fragment

I have Fragment XYZFragment where i display the list view.On the Listview item click i replace the Fragment like this.
Fragment fragment=new XYZFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft= fragmentManager.beginTransaction();
ft.addToBackStack(null);
ft.replace(R.id.content_frame, fragment).commit();
But my problem is when i click back button the fragment reload the listview.It is never happen when i used to use Activity.
So my question is how to save the instance of previous fragment so that it will prevent the reloading of Data.
without seeing your code we can't help you out but from your question i can figure out the problem, this solution may help you out.
create stack such that
private static Stack<Fragment> myFragStack;
myFragStack = new Stack<Fragment>();
//To Load the fragment
public void loadFragment(Fragment fragment){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
myFragStack.lastElement().onPause();
ft.hide(myFragStack.lastElement());
myFragStack.push(fragment);
}
//onBackPressed
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (myFragStack.size() > 1) {
ft.remove(myFragStack.pop());
myFragStack.lastElement().onResume();
ft.show(myFragStack.lastElement());
ft.commit();
}
}
It's a sample code.. you can change it as per your requirement.
ft.replace() will completely remove the view & will lose the context so you can't maintain your list state, but using stacks maintaining fragments with hide-show will solve your problem.

Reset/reload fragment container

How can I reset or reload a fragment container, to make it empty.
I have a master detail view and I want to reset the detail container to empty on a menu item click.This works in some cases and does not in some.
NullFragment fragment = new NullFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(R.id.item_detail_container,
fragment);
int count = fragmentManager.getBackStackEntryCount();
fragmentManager.popBackStackImmediate(count, 0);
fragmentTransaction.commit();
Usually you simply remove the fragment from it.
For example do something like
getFragmentManager().beginTransaction().remove(getFragmentManager().findFragmentById(R.id.your_container)).commit();
this will remove the fragment from the your_container holding it.
This gets the fragment currently present in your_container
getFragmentManager().findFragmentById(R.id.your_container)
and this remove the fragment
getFragmentManager().beginTransaction().remove(fragment).commit();
EDIT
Also sometimes it is useful to ensure all transactions are performed and finished, this can be done by using
getFragmentManager().executePendingTransactions();

Removing a Fragment from the back stack

I have a 3 fragments in an activity when the a tablet is held in portrait. However I only have 2 of these fragments when in landscape. The problem I am having is when going from portrait to landscape the activity is creating the 3rd fragment. I receive and error as this fragment cannot be created.
I have worked out that this fragment is being created because it is in the back stack.
I have tried to remove the fragment in the onDestroy method by using
FragmentTransaction f = fragmentManager.beginTransaction();
f.remove(mf);
f.commit();
However the I get an error saying that I cannot use this function after the onSaveInstanceState
What would be the correct way of taking this fragment out of the back stack?
Update
I should probably add that the fragment I am having problems with is a mapFragment from this libary
https://github.com/petedoyle/android-support-v4-googlemaps
The way I use it is like so
mf = MapFragment.newInstance(1, true);
ft = fragmentManager.beginTransaction();
ft.replace(R.id.mapContainer, mf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack("map");
ft.commit();
You add to the back state from the FragmentTransaction and remove from the backstack using FragmentManager pop methods:
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove(myFrag);
trans.commit();
manager.popBackStack();
I created a code to jump to the desired back stack index, it worked fine to my purpose.
ie. I have Fragment1, Fragment2 and Fragment3, I want to jump from Fragment3 to Fragment1
I created a method called onBackPressed in Fragment3 that jumps to Fragment1
Fragment3:
public void onBackPressed() {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-2).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
In the activity, I need to know if my current fragment is the Fragment3, so I call the onBackPressed of my fragment instead calling super
FragmentActivity:
#Override
public void onBackPressed() {
Fragment f = getSupportFragmentManager().findFragmentById(R.id.my_fragment_container);
if (f instanceof Fragment3)
{
((Fragment3)f).onBackPressed();
} else {
super.onBackPressed();
}
}
you show fragment in a container (with id= fragmentcontainer) so you remove fragment with:
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
fragmentTransaction.remove(fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
In case you ended up here trying to figure out how to remove fragment(s) from backstack and you are using Android Jetpack Navigation component you could just use app:popUpTo and app:popUpToInclusive in action node of navigation graph xml to specify fragments that you want to pop out of back stack.
https://developer.android.com/guide/navigation/navigation-navigate#pop
Check this too
https://stackoverflow.com/a/51974492/4594986
What happens if the fragment that you want to remove is not on top of the stack?
Then you can use theses functions
popBackStack(int arg0, int arg1);
popBackStack(String arg0, int arg1);

Categories

Resources