move Android fragment to a different container Can't change container ID of fragment

Matthieu picture Matthieu · Nov 28, 2012 · Viewed 12.2k times · Source

Here is what I would like my application to do on a tablet. Fragment (0) has some menu that would display fragments (1)...(n) like this:

-----------------
|   |   |   |   |
|   |   |   |   |
|(0)| X | X | X |
|   |   |   |   |
|   |   |   |   |
-----------------
 becomes
-----------------
|   |   |   |   |
|   |   |   |   |
|(0)|(1)| X | X |
|   |   |   |   |
|   |   |   |   |
-----------------
 and then
-----------------
|   |   |   |   |
|   |   |   |   |
|(0)|(2)|(1)| X |
|   |   |   |   |
|   |   |   |   |
-----------------
 etc... 

Fragment0 never moves, the other ones are shifted to the right. Fragments going off the edge to the right will be destroyed.

So I setup my XML layout with a horizontal LinearLayout and containing 4 FrameLayout with the proper IDs (fragment0... fragment3)

I can instantiate and display fragment0 and then fragment1, but I am not able to shift it to the right after, I get:

ERROR/AndroidRuntime(343): FATAL EXCEPTION: main
java.lang.IllegalStateException: Can't change container ID of fragment ...

The only related questions I have found are this one and that one, tried all the different solutions offered with no luck.

Tried FragmentTransaction.remove() followed by .add(), tried .replace(), tried them in different orders and to commit half-way through (even trying to commit twice as somebody suggested), tried to call addToBackStack() ... still no luck.

Question is whether it is possible to move the fragments like this with a FragmentTransaction. If yes, what am I doing wrong (and bonus, is it possible to animate that?). If no, what would be the proper way to implement this?

Note that I don't want to re-instantiate the fragments every time (each do some queries on the web that can take some time). It's possible to extract all the data back to the activity to recreate one, but I'd rather not do that if possible...

Answer

Pavan Jaju picture Pavan Jaju · Oct 4, 2013

Yes container of the fragment can be changed using remove() function.

The problem here is commit(). It is an asynchronous call, and will schedule it to be on main thread. So to force the FragmentManager to do this immediately before adding it to the other container.

For this we will have to use executePendingTransactions() function. After calling this try adding the fragment to new container.

Docs : executePendingTransactions()

Code Sample :

FragmentManager fManager = getSupportFragmentManager();
FragGroups fragGroups = (FragGroups) fManager.findFragmentByTag("groups");
if (fragGroups != null) {
     fManager.beginTransaction().remove(fragGroups).commit();
     fManager.executePendingTransactions();
} else {
     fragGroups = new FragGroups();
}
if (mTwoPane) {
    fManager.beginTransaction().replace(R.id.fragment_container_groups, fragGroups, "groups").commit();
} else {
    fManager.beginTransaction().replace(R.id.fragment_container, fragGroups, "groups").commit();
}

Enjoy. Feed-backs are welcomed

Edit

I would like a add a point here. As I had same problem, came across to this thread and applied suggested changes. Problem still persisted. Then i looked into last comment down this thread that solved my problem: remove addToBackStack() method while committing a transaction or if you intentionally using it, remove the fragment from back stack before adding it to another container. Hope it will help to future reader.