屏幕旋转后,ViewPager 仍然保留旧的 Fragments。

5
我正在使用 ViewPagerFragmentStatePagerAdapter 来显示片段。最初添加了两个片段 Fragment1 和 Fragment2,然后在从服务器接收响应后将第三个片段 Fragment3 添加到第二个位置。因此,在添加所有页面之后,ViewPager 中的片段顺序应为 --> Fragment1、Fragment3、Fragment2。
问题是,在添加 Fragment1 和 Fragment3 并在添加第三个片段到第二个位置之前,应用程序进行服务器调用并多次旋转屏幕后,即使添加了第三个片段,它仍然显示旧的 Fragment2 副本,该副本最初位于第二个位置,并且第二个位置和第三个位置有 Fragment2 的新副本。因此,Fragment3 在 ViewPager 中不会显示。添加第三个片段后的顺序为 --> Fragment1、Fragment2 的旧副本、新的 Fragment2。
我重写了 Activity 的 onSaveInstanceState 方法,并调用了 super.onSaveInstanceState
另外,我尝试从 getItemPosition 返回 POSITION_NONE。我在某个地方读到 ViewPager 保存片段的副本。还通过调试检查了当出现问题时 ViewPager 包含 2 个 Fragment2 的副本,即使 FragmentStatePagerAdaptergetItem 为每个位置返回不同的片段,但在第二个位置仍然显示旧片段。为了测试目的,在 getItem 中,我为所有位置返回 Fragment1,以便所有 3 个页面都应相同,但即使在上述步骤中重现问题时,第二个位置仍显示 Fragment2 的旧副本。
因此,如何清除 ViewPager,使其不保存旧的片段。如何刷新 ViewPager,使其不保留带有片段的旧副本。我认为问题出在 onSaveInstanceState 上,但我需要它。如何在保存视图时排除 ViewPager。我尝试过 mViewPager.setSaveEnabled(false),但它会占用太多内存。
我发现问题是适配器的 instantiateItem 方法没有调用 getItem,因此返回旧的片段。
下面是解决方案代码:
 @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Object obj = super.instantiateItem(container, position);
            Fragment fragment = mFragments.get(position);

            if((obj!=null && fragment!=null) && !(obj.getClass().getSimpleName().equals(fragment.clss.getSimpleName()))){
                destroyItem(container, position, obj);
                return super.instantiateItem(container, position);
            }else{
                return obj;
            }
        }

你有检查过这个吗? - Snehal Poyrekar
你删掉了你的评论..现在可以用了吗? - Snehal Poyrekar
问题在于适配器的instantiateItem方法没有调用getItem,因此返回了旧的片段。我正在寻找一种方法来使其调用getItem。 - anujprashar
请阅读以下链接中的顶部回答,特别注意提到的“重叠视图”。您将需要对添加的视图进行显式删除... https://dev59.com/WWcs5IYBdhLWcg3w1nhq#14295368 - Robert Rowntree
实际上,这个答案是保留片段的推荐方法:https://dev59.com/kuo6XIcBkEYKwwoYSCc1#29288093 - Nikita Barishok
2个回答

1
我解决了这个问题,我在这里发布我的解决方案。我重写了FragmentStatePagerAdapterinstantiateItem方法,在其中获取从列表中维护的片段对象的位置处的对象,并将其类名与super.instantiateItem的类名进行比较。
如果类名不同,则意味着super.instantiateItem返回了重复的片段。因此,我在该位置调用destroyItem,然后再次调用super.instantiateItem,并将其从instantiateItem返回。 FragmentStatePagerAdapter返回旧片段,因为框架代码中的arraylist mFragments具有重复的片段,并且它只返回当前位置的片段。我认为它应该在返回之前将列表中该位置处的片段与当前显示的片段进行比较。

2
你能给我展示一些(虚拟的)代码吗?我不理解你只用文字的解决方案(抱歉,我的英语不好)。 - Poutrathor
@Poutrathor 抱歉回复晚了。我已经在答案中添加了代码。 - anujprashar
@k2ibegin 代码已经在上面的问题陈述中给出。 - anujprashar
@anujprashar 抱歉,我也不明白你的意思。你能提供一个演示此问题的样例应用程序或者展示你所做的代码块吗? - Tim Kist

1

只有在FragmentPagerAdaper中覆盖此方法。

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
       // TODO Auto-generated method stub
       super.destroyItem(ViewGroup container, int position, Object object);
}

然后从您的代码中删除super.destroyItem(ViewGroup container, int position, Object object);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接