Android platform: 3.1
I am trying to move a fragment from a container A to a container B. Here follows the code to accomplish this:
private void rea
I found the problem was I needed two FragmentTransactions. I was trying to remove() and commit() twice on the same one.
// create new fragment
MyFragment myNewFragment = MyFragment.newInstance(this, data, true);
FragmentManager fm = this.getSupportFragmentManager();
// clear the back stack
fm.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
//fragmentTransaction is created for the removal of the old
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.remove(myOldFragment);
fragmentTransaction.commit();
fm.executePendingTransactions();
// fragmentTransaction2 is created to add the new one
FragmentTransaction fragmentTransaction2 = fm.beginTransaction();
fragmentTransaction2.add(R.id.fragment_frame, myNewFragment);
fragmentTransaction2.commit();
fm.executePendingTransactions();
My solution to this problem is to re-create the fragment while keeping its state:
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.remove(old);
Fragment newInstance = recreateFragment(old);
ft.add(R.id.new_container, newInstance);
ft.commit();
With the following helper function:
private Fragment recreateFragment(Fragment f)
{
try {
Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(f);
Fragment newInstance = f.getClass().newInstance();
newInstance.setInitialSavedState(savedState);
return newInstance;
}
catch (Exception e) // InstantiationException, IllegalAccessException
{
throw new RuntimeException("Cannot reinstantiate fragment " + f.getClass().getName(), e);
}
}
It works for me, at least with the latest support library (r11), although I didn't test much yet.
The extra cost is to instantiate the fragment twice.
Based on Fragment Developer Guide which it states:
If you do not call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back
So I assume that your frag object is destroyed after the calls to
ft.remove(frag); //stacco il frammento dal container A
ft.commit();
But you say that it works in ICS and this is strange. Why don't you try the replace method and see what's happens?
Hope this helps...
after trying all the answers from similar questions, looks like i've found a way to do the trick.
First issue - you really have to commit and execute remove transaction before trying to add fragment to another container. Thanks for that goes to nave's answer
But this doesn't work every time. The second issue is a back stack. It somehow blocks the transaction.
So the complete code, that works for me looks like:
manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
manager.beginTransaction().remove(detailFragment).commit();
manager.executePendingTransactions();
manager.beginTransaction()
.replace(R.id.content, masterFragment, masterTag)
.add(R.id.detail, detailFragment, activeTag)
.commit();
I'll need to prototype something later if this doesn't help but one thing I would try is not doing this as separate transactions because even though you call executePendingTransactions() it shouldn't be a blocking call, so while it's doing its thing the rest of your code will begin to execute, which includes trying to add the Fragment to a new container while it might still exist in its current container.
Since you're doing all of this from a single method, you could try doing the remove and add in a single FragmentTransaction, so that you know it will execute in the order that you want it to, and so that you know when the Fragment has been removed from one container and can add it to a new one and then commit. Else, if you really want to do it as two separate transactions, the base Fragment class has an isRemoving() method that will tell you if the Fragment is being removed from it's container and you can wait until that becomes false so that you know it's been removed. That said, you're starting to introduce synchronization issues if now one transaction depends on another before it can execute, and I don't see any reason not to just to the remove and add as a single transaction.
Thanks, David
This can happen when try to add the same fragment
more than once.
public void populateFragments() {
Fragment fragment = new Fragment();
//fragment is added for the first time
addFragment(fragment);
// fragment is added for the second time
// This call will be responsible for the issue. The
addFragment(fragment);
}
public void addFragment(Fragment fragment) {
FrameLayout frameLayout = AppView.createFrameLayout(context);
view.addView(frameLayout);
getSupportFragmentManager().beginTransaction().add(frameLayout.getId(), fragment).commit();
}