I have a HorizontalScrollView
containing a (horizontal) LinearLayout
which I use as the container for adding multiple fragments. Upon some changes, I need to remove all fragments from that container and add new ones. However, there seems to be a problem with ordering when I'm removing the old fragments.
Here are the scenarios:
- app startup
- correctly adding fragments
A1
,B1
,C1
,D1
in this order
- correctly adding fragments
- change content
- if not removing initial fragments, but adding
A2
,B2
,C2
(as a single transaction), it will showA1
,B1
,C1
,D1
,A2
,B2
,C2
- if removing initial fragments (either as a separate or using the same transaction), then adding
A2
,B2
,C2
, it will showC2
,B2
,A2
- if not removing initial fragments, but adding
For now I found a workaround, where I'm adding the new fragments first then removing the old ones (still as part of the same transaction) and that is working properly.
EDIT: The workaround doesn't work all the time.
I'm using android.support.v4.app.Fragment
.
Any ideas on what's happening?
other way to fix this issue:
replace ArrayList mAvailIndices by ReverseOrderArrayList
}
As an alternative workaround, you could try adding views to the LinearLayout and then add each fragment to the correct view. It's not ideal, but it seems as though you cannot rely on the ordering of Fragment creation. Something like the following:
Then later, when you remove all fragments, ensure you remove the corresponding views too.
Note: the code may syntactically wrong, I just typed this straight into StackOverflow. The idea is sound, albeit an average solution. Interesting question though - I will probably look into this more when I get more time. Find out exactly what happens. If I do, I'll post more information here.
Edit:
Rotation should be easy to handle if you let the system handle it for you. Add a unique id to each of the generated views.
Now use that counter to set the ids when creating the views:
Had a similar issue, the solution I ended up using was to have multiple transactions. In my case, it was only A, B, C. And I used one transaction to add A, one to add B, one to add C.
The order of transactions seems to be reliable.
Probably requires more complex code, if you wish to have backstack working. But a backstack tag on the first transaction should allow proper handling there, too.
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:
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
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:
Where
FragmentTransactionBugFixHack
looks like this: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.
Here is a slightly-modified version of Radu's answer where I added the recursion part at the end. This reorders indices of the given fragment manager, and all its fragments' childFragmentMangers, and all of those fragments' childFragmentManagers, and so on.
This is a new class that you add to your project (You can add a package
android.support.v4.app
to your source code'sjava
folder, and put it in that package, and that worked for me):For solving the problem of when it recreates fragments out of order when the device is rotated, just put this in your Activity class which manages the fragment (Credit goes to Andrey Uglev's comment in Radu's answer):