在FragmentStatePagerAdapter中随机位置添加或删除页面时出现问题

时间:2015-08-20 13:09:21

标签: android adapter fragmentstatepageradapter

我花了很多时间在谷歌的stakcoverflow和android doc上关于在FragmentStatePagerAdapter的RANDOM位置添加或删除页面的相关问题/答案。
它工作正常,但在一个场景中失败 场景-1有效:
例如,添加4页(碎片) 删除位于位置3的最后位置的页面 再次在页面末尾再添加一页 删除位于位置3的最后位置的页面 ...。我重复这些步骤,它的工作原理非常好。

但是情景-2失败了:
例如,添加4页(碎片) 删除除最后位置以外的任何页面,比如位置2.正常工作。页面不再被看到。
再次在页面末尾再添加一页。在这里失败..我看到空白页面。

我在某种程度上对它进行了分析,我发现getItem()在失败时没有被调用。因为getItem()是创建并返回新片段的那个,因此它不会获得新片段,因此它显示为空白。我看到了instantiateItem()的实现,并观察到如果可用no片段的大小超过创建片段请求的位置,则不调用getItem()。但不确定它何时发生或如何发生。

这是我的适配器的getItem()和getItemPosition()。我有自己的一组ArrayList片段(FragmentStatePagerAdapter维护它自己的片段列表集)... mFragments就是下面的代码。在我调用notifyDataItemChanged()之后,我观察到了。

@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);
}

如果你有任何线索,请多花几分钟帮助我。 下面是日志片段。第一个是当我在第3个位置删除页面时(页面中间,而不是最后一页)。秒秒是我尝试添加新页面的时候。你可以观察当我在第二个日志片段中添加页面时没有调用getItem()。

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 个答案:

答案 0 :(得分:0)

我无法猜测这是一个框架问题。但是在我花了很多时间分析之后,我发现FragmentStatePagerAdapter中的destroyItem()没有删除getItemPosition()返回POSITION_NONE的片段。它指定null但不删除该项。下面是原始FragmentStatePagerAdapter的方法。而且你看到我已经添加了两行代码来明确删除片段。

    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);
    }

正如我在日志中清楚地看到删除页面后的页面索引没有正确重新排序。

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}

我删除了第3个位置。上面是容器中的片段列表,您可以在其中看到错过的索引#3。那是因为有一个null的元素。它没有被完全删除,但是如果你观察的话它只是由原始代码引用。
我的情况是我应该能够删除任何页面,并且应该能够在最后添加新页面 因此,我使用上面的destroyItem()方法显式删除了对象。它奏效了。

最后但并非最不重要的是,在得到答案后我找到了这个链接。见https://code.google.com/p/android/issues/detail?id=37990。对于许多开发人员来说,这似乎是多个问题,但对于他们的特定情况,他们也有解决方案。查找您的方案是否涵盖在那里。如果没有,你可以做我做的事情。提升完整的FragmentStatePagerAdapter.java并根据需要进行修改。