从FragmentStatePagerAdapter中删除片段

时间:2014-09-19 07:36:09

标签: android android-fragments

更新

经过与这个问题的一些重大斗争和SO用户的帮助后,我设法解决了这个问题。 这就是我clearProgressUpTo现在的样子。

    public void clearProgressUpTo(int progress) {
    boolean deleted = false;

    for (int i = fragments.size() - 1; i > 0; i--) {
        int key = fragments.keyAt(i);
        if (key != progress) {
            fragments.delete(key);
            deleted = true;
        } else {
            break;
        }
    }

    if (deleted)
        notifyDataSetChanged(); //prevents recursive call (and IllegalStateException: Recursive entry to executePendingTransactions)

    while (mSavedState.size() > progress) {
        mSavedState.remove(mSavedState.size()-1);
    }

}

我在notifyDataSetChanged后执行此操作的原因是因为initiateItem再次填充了mSavedState。我确信在通知我的adapter之后,Fragments没有任何一个{。}}。

此外,如果您想这样做,请将mSaveState更改为protected,这样您就可以从扩展类中获取它(在我的情况下为VerticalAdapter)。

我忘了提到我正在使用FragmentStatePagerAdapter fix by Adam Speakman来解决我的问题。

/////////////////////////////////////////////// ////// 问题部分 /////////////////////////////////// ///////////////////

我遇到的问题是我需要完全删除Fragments中保留的一些FragmentStatePagerAdapter

我已经对其进行了POSITION_NONE修复,但旧片段似乎仍然完好无损。

建筑

由于构建我的ViewPager是不寻常的,因此我被迫放置在我的VerticalAdaterFragmentStatePagerAdapter SparseArray public class VerticalAdapter extends FragmentStatePagerAdapter { private SparseArray<Fragment> fragments = new SparseArray<Fragment>(); ... @Override public Fragment getItem(int position) { return getFragmentForPosition(position); } @Override public int getCount() { return fragments.size(); } ,其中包含我的所有碎片。

Fragments

问题

我制作了一个特殊的方法,负责清除FragmentStatePagerAdapter中某些点的所有ArrayList。它运作良好,但我无法摆脱的问题是清除FragmentStatePagerAdapter内的SparseArray。即使我清除了ArrayList,我FragmentStatePagerAdapter延伸的VerticalAdapter Fragments仍然持有我不想拥有的Fragments。因此,当我创建新的public void clearProgressUpTo(int progress) { boolean deleted = false; for (int i = fragments.size() - 1; i > 0; i--) { int key = fragments.keyAt(i); if (key != progress) { fragments.delete(key); deleted = true; } else { break; } } if (deleted) notifyDataSetChanged(); //prevents recursive call (and IllegalStateException: Recursive entry to executePendingTransactions) } 时,它们具有旧的状态。

private Fragment getFragmentForPosition(int position) {
    return fragments.get(getKeyForPosition(position));
}

public int getKeyForPosition(int position) {
    int key = 0;
    for (int i = 0; i < fragments.size(); i++) {
        key = fragments.keyAt(i);
        if (i == position) {
            return key;
        }
    }
    return key;
}

如果您需要更多信息/代码,请在评论中告诉我,我会尽量提供尽可能多的信息。

我不知道如何解决这个问题,所以任何输入都会受到赞赏。

修改

添加请求的代码。

{{1}}

3 个答案:

答案 0 :(得分:7)

您的问题不是由您使用SparseArray引起的。实际上,您遇到了FragmentStatePagerAdapter的错误。我花了一些时间阅读FragmentStatePagerAdapter,ViewPager和FragmentManagerImpl的源代码,然后找到了你的新片段具有旧片段状态的原因:

FragmentStatePagerAdapter在删除旧片段时保存它们的状态,如果稍后向适配器添加新片段,则保存的状态将传递到同一位置的新片段。

我搜索了这个问题并找到了解决方案,这里是它的链接: http://speakman.net.nz/blog/2014/02/20/a-bug-in-and-a-fix-for-the-way-fragmentstatepageradapter-handles-fragment-restoration/

源代码可以在这里找到: https://github.com/adamsp/FragmentStatePagerIssueExample/blob/master/app/src/main/java/com/example/fragmentstatepagerissueexample/app/FixedFragmentStatePagerAdapter.java

此解决方案的关键思想是重写FragmentStatePagerAdapter并使用String标记来标识适配器中的每个片段。因为每个片段都有不同的标记,所以很容易识别新的片段,然后不将已保存的状态传递给新的片段。

最后,感谢作为该解决方案作者的Adam Speakman。

答案 1 :(得分:7)

FragmentStatePageAdapter在销毁片段时保存片段的状态,因此当片段重新创建时,后者将应用已保存的状态。

片段状态存储在私有成员变量中。因此,我们无法扩展当前实现以添加删除已保存状态的功能。

我克隆了当前的FragmentStatePagerAdapter实现,并包含了已保存的状态删除功能。这是gist reference

   /**
     * Clear the saved state for the given fragment position.
     */
    public void removeSavedState(int position) {
        if(position < mSavedState.size()) {
            mSavedState.set(position, null);
        }
    }

clearProgressUpTo方法中,每当从稀疏数组中删除片段时,请调用此方法,这会清除该片段的已保存状态。

答案 2 :(得分:0)

调用notifyDataSetChanged()时,适配器开始使用destroyItem(ViewGroup container, int position, Object object)删除其片段。

但是,每个片段的实例状态由FragmentStatePagerAdapter内部保留,稍后在instantiateItem(ViewGroup container, int position)中使用。

只需保存要删除的项目的位置,然后调用notifyDataSetChanged()。在最后一项销毁之后,立即从FragmentStatePagerAdapter中检索所需的已保存实例状态,并替换为null。

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);

    if(position == getCount() - 1 && i >= 0){
        Bundle state = (Bundle) saveState();
        Fragment.SavedState[] states = (Fragment.SavedState[]) state.getParcelableArray("states");
        if (states != null)
            states[i] = null;
        i = -1;
        restoreState(state, ClassLoader.getSystemClassLoader());
    }

注意:getItemPosition(Object object)必须返回PagerAdapter.POSITION_NONE