I enabled debugging on the FragmentManager and I found the problem.
Here's an excerpt from the logs, notice how the fragment index is allocated in reverse order:
V/FragmentManager? Freeing fragment index TimeTracesChartFragment{42ac4910 #7 id=0x7f080044}
V/FragmentManager? add: RealTimeValuesFragment{42a567b0 id=0x7f080044}
V/FragmentManager? Allocated fragment index RealTimeValuesFragment{42a567b0 #7 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d35c38 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d35c38 #6 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d35e98 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d35e98 #5 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d36220 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d36220 #4 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d39d18 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d39d18 #3 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d3a170 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d3a170 #2 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d3a528 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d3a528 #1 id=0x7f080044}
V/FragmentManager? moveto CREATED: TimeTracesChartFragment{42d3a528 #1 id=0x7f080044}
And here is the culprit code:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/app/FragmentManager.java#FragmentManagerImpl.makeActive%28android.support.v4.app.Fragment%29
void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}
if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f);
} else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}
Notice how the available indices are taken from the back of the list. It should probably choose the lowest index available so that it would preserve ordering.
Now to think of a workaround...
EDIT:
Here's a workaround:
Create two separate transactions, one for the removals and then one for the additions, then do this:
removalTxn.commit();
getSupportFragmentManager().executePendingTransactions();
FragmentTransactionBugFixHack.reorderIndices(getSupportFragmentManager());
//create additionTxn
additionTxn.commit();
Where FragmentTransactionBugFixHack
looks like this:
package android.support.v4.app;
import java.util.Collections;
public class FragmentTransactionBugFixHack {
public static void reorderIndices(FragmentManager fragmentManager) {
if (!(fragmentManager instanceof FragmentManagerImpl))
return;
FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
if (fragmentManagerImpl.mAvailIndices != null)
Collections.sort(fragmentManagerImpl.mAvailIndices, Collections.reverseOrder());
}
}
It's not ideal, because of the two separate transaction it will flicker to white (or whatever your container's background is), but at least it will order them properly.