0
votes

I have spent big time on related questions/answers in stakcoverflow and android doc from google on about adding or deleting pages at RANDOM positions in FragmentStatePagerAdapter.
It works fine but fails for one scenario.
Scenario-1 that works:
Add, say, 4 pages (Fragments).
Delete the page at last position that is at position 3.
Add one more page at the end of page again.
Delete the page at last position that is at position 3.
…. I repeat this steps and it works perfectly fine.

But scenario-2 it fails:
Add, say, 4 pages (Fragments).
Delete any page other than last position, say, position 2. Works fine. Page is no more seen.
Add one more page at the end of page again. FAILED here..I see blank page.

I did analyse it to some extent and I could find that getItem() is not being called when it failed. As getItem() is the one which creates and returns the new fragment so it does not get the new fragment so it shows blank. I saw the implementation of instantiateItem() and observed that getItem() is not called if the size of the available no of fragments is more than the position requested to create the fragment for. But not sure when it happens or how.

Here is my getItem() and getItemPosition() from my adapter. I have my own set of ArrayList of fragments (FragmentStatePagerAdapter maintains it’s own set of fragment list)…mFragments is that in the below code. After I call notifyDataItemChanged() I observed.

@Override
public int getItemPosition(Object object) {
    if (object instanceof InnerFragment) {
        if (!mFragments.contains(object)) {
            Log.d(TAG, "getItemPosition Frag " + object + " is REMOVED and item count is " + MainFragment.mPager.getChildCount());
            return POSITION_NONE;
        } else {
            Log.d(TAG, "getItemPosition Frag " + object + " is AVAILABLE and item count is " + MainFragment.mPager.getChildCount());
            Log.d(TAG, "getItemPosition .....position of this fragment is : " + mFragments.indexOf(object));
            return mFragments.indexOf(object);
        }
    }
    Log.d(TAG, "getItemPosition object is not InnerFragment..");
    return super.getItemPosition(object);
}

@Override
public Fragment getItem(int position) {
    Log.d(TAG, "getItem for position " + position + "..create NEW FRAG and item count is " + MainFragment.mPager.getChildCount());
    return createNewPage(position);
}

Please spare few mins and help me if you get any clue. below is the log snippets. First one is when I have deleted the page at 3rd position (which is middle of pages, not the last page). And seconds one is when I tried to add new page. You can observe getItem() is not called when I added page in second log snippet..

08-20 12:09:55.062    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   Places/count before handlePlaces : 6 and fragments : [InnerFragment{3e50591d #0 id=0x7f10008d}, InnerFragment{ccaf792 #1 id=0x7f10008d}, InnerFragment{16c61563 #2 id=0x7f10008d}, InnerFragment{3a6d7560 #3 id=0x7f10008d}, InnerFragment{229e6a19 #4 id=0x7f10008d}, InnerFragment{2a1cfade #5 id=0x7f10008d}]
08-20 12:09:55.062    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   Place deleted : 110665902
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   Places/count after handlePlaces : 5 and fragments : [InnerFragment{3e50591d #0 id=0x7f10008d}, InnerFragment{ccaf792 #1 id=0x7f10008d}, InnerFragment{16c61563 #2 id=0x7f10008d}, InnerFragment{229e6a19 #4 id=0x7f10008d}, InnerFragment{2a1cfade #5 id=0x7f10008d}]
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{3e50591d #0 id=0x7f10008d} is AVAILABLE and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 0
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{ccaf792 #1 id=0x7f10008d} is AVAILABLE and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 1
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{16c61563 #2 id=0x7f10008d} is AVAILABLE and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 2

08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{3a6d7560 #3 id=0x7f10008d} is REMOVED and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   destroyItem object InnerFragment{3a6d7560 #3 id=0x7f10008d}to be rmeoved from 3

08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{229e6a19 #4 id=0x7f10008d} is AVAILABLE and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 3
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{2a1cfade #5 id=0x7f10008d} is AVAILABLE and item count is 6
08-20 12:09:55.072    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 4




08-20 12:10:10.152    3919-3919/ com.example.pack D/MainActivity﹕   all received for Place{placeId=119680744, placeName='Moskva', localName='null', latitude=55.75222, longitude=37.61556, moh=150, countryId=1426, categoryId=1552, categoryName='Hovedstad', country='Russia', priority=0, adm1='null', adm2='Moscow'}
08-20 12:10:15.152    3919-3919/ com.example.pack D/MainActivity﹕   all received for Place{placeId=113259163, placeName='Stockholm', localName='null', latitude=59.33258, longitude=18.0649, moh=21, countryId=428, categoryId=1552, categoryName='Hovedstad', country='Sweden', priority=0, adm1='Stockholm', adm2='Stockholm municipality'}
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   Places/count before handlePlaces : 5 and fragments : [InnerFragment{3e50591d #0 id=0x7f10008d}, InnerFragment{ccaf792 #1 id=0x7f10008d}, InnerFragment{16c61563 #2 id=0x7f10008d}, InnerFragment{229e6a19 #4 id=0x7f10008d}, InnerFragment{2a1cfade #5 id=0x7f10008d}]
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   New Place added : 105109562
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   Places/count after handlePlaces : 6 and fragments : [InnerFragment{3e50591d #0 id=0x7f10008d}, InnerFragment{ccaf792 #1 id=0x7f10008d}, InnerFragment{16c61563 #2 id=0x7f10008d}, InnerFragment{229e6a19 #4 id=0x7f10008d}, InnerFragment{2a1cfade #5 id=0x7f10008d}]
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{3e50591d #0 id=0x7f10008d} is AVAILABLE and item count is 5
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 0
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{ccaf792 #1 id=0x7f10008d} is AVAILABLE and item count is 5
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 1
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{16c61563 #2 id=0x7f10008d} is AVAILABLE and item count is 5
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 2
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{229e6a19 #4 id=0x7f10008d} is AVAILABLE and item count is 5
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 3
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition Frag InnerFragment{2a1cfade #5 id=0x7f10008d} is AVAILABLE and item count is 5
08-20 12:10:25.112    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   getItemPosition .....position of this fragment is : 4

08-20 12:10:25.122    3919-3919/ com.example.pack D/MyFragStatePagerAdapter﹕   instantiateItem for position 5 and item count is 5
1

1 Answers

0
votes

I could not guess that it would be a framework issue. But after I spent hard time on analyzing it I could find that destroyItem() in FragmentStatePagerAdapter is not removing the fragment for which getItemPosition() returned POSITION_NONE. It assigns null but it does not remove the item. Below is that method from original FragmentStatePagerAdapter. And you see I have added two lines of code to remove the fragment explicitly.

    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment)object;
        if(this.mCurTransaction == null) {
            this.mCurTransaction = this.mFragmentManager.beginTransaction();
        }

        while(this.mSavedState.size() <= position) {
            this.mSavedState.add(null);
        }

        this.mSavedState.set(position, this.mFragmentManager.saveFragmentInstanceState(fragment));
        this.mFragments.set(position, null);

        /***** Below are the two lines I have added  
        in addition to this original method from Android. ******/
        this.mFragments.remove(position);
        this.mSavedState.remove(position);

        this.mCurTransaction.remove(fragment);
    }

As I could see clearly in the log that the index of pages after a page is deleted is not reordered properly.

InnerFragment{3e50591d #0 id=0x7f10008d}
InnerFragment{ccaf792 #1 id=0x7f10008d}
InnerFragment{16c61563 #2 id=0x7f10008d}
InnerFragment{229e6a19 #4 id=0x7f10008d}
InnerFragment{2a1cfade #5 id=0x7f10008d}

I had deleted the 3rd position. Above is the list of fragments in the container where you can see the index #3 is missed. That is because there is an element which is null..it is not completely removed but it is just null referenced by the original code if you observe.
My case is that I should be able to delete any page and should be able to add a new page at the end.
So, I explicitly removed the object with the lines as in above destroyItem() method. And it worked.

Last but not least, I found this link after I got my answer. See this https://code.google.com/p/android/issues/detail?id=37990. THere are multiple issues it seems are occuring for many developers but for their specific scenarios and they have solutions too. Find if your scenario covered there. If not you can do what I did..lift the complete FragmentStatePagerAdapter.java and modify according to the needs.