I figured out exactly what is going wrong. The FragmentStatePagerAdapter 
caches the fragments and saved states in ArrayLists: mFragments and 
mSavedState. But when the fragments are reordered, there is no mechanism 
for reordering the elements of mFragments and mSavedState. Therefore, the 
adapter will provide the wrong fragments to the pager.

Is http://code.google.com/p/android/ the appropriate place to file this 
issue?

Here is my fix. I add a getItemId() function to FragmentStatePagerAdapter. 
(This mirrors the reordering implementation in FragmentPagerAdapter.) I 
store an array of the itemIds at all times. Then, in startUpdate(), I check 
if the itemIds array has changed. If it has, then I reorder mFragments and 
mSavedState accordingly.

This fix is fairly inefficient because startUpdate() is called many times 
by ViewPager. Actually, we only need to perform the 
mItemIds/mFragments/mSavedState reordering when ViewPager.dataSetChanged() 
is called. But I wanted to avoid having to modify ViewPager as well.

Note that these changes cannot be achieved by subclassing 
FragmentStatePagerAdapter because we need access to the private members 
mFragments and mSavedState.

Here are my changes:

public abstract class FragmentStatePagerAdapter extends PagerAdapter {
    private long[] mItemIds = new long[] {};
    
    /**
     * Return a unique identifier for the item at the given position.
     */
    public long getItemId(int position) {
        return position;
    }
    
    @Override
    public void startUpdate(ViewGroup container) {
        long[] newItemIds = new long[getCount()];
        for (int i = 0; i < newItemIds.length; i++) {
            newItemIds[i] = getItemId(i);
        }
        
        if (!Arrays.equals(mItemIds, newItemIds)) {
            ArrayList<Fragment.SavedState> newSavedState = new 
ArrayList<Fragment.SavedState>();
            ArrayList<Fragment> newFragments = new ArrayList<Fragment>();
            
            for (int oldPosition = 0; oldPosition < mItemIds.length; 
oldPosition++) {
                int newPosition = POSITION_NONE;
                for (int i = 0; i < newItemIds.length; i++) {
                    if (mItemIds[oldPosition] == newItemIds[i]) {
                        newPosition = i;
                        break;
                    }
                }
                if (newPosition >= 0) {
                    if (oldPosition < mSavedState.size()) {
                        Fragment.SavedState savedState = 
mSavedState.get(oldPosition);
                        if (savedState != null) {
                            while (newSavedState.size() <= newPosition) {
                                newSavedState.add(null);
                            }
                            newSavedState.set(newPosition, savedState);
                        }
                    }
                    if (oldPosition < mFragments.size()) {
                        Fragment fragment = mFragments.get(oldPosition);
                        if (fragment != null) {
                            while (newFragments.size() <= newPosition) {
                                newFragments.add(null);
                            }
                            newFragments.set(newPosition, fragment);
                        }
                    }
                }
            }
            
mItemIds = newItemIds;
            mSavedState = newSavedState;
            mFragments = newFragments;
        }
    }
}

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to