ViewPager + FragmentStatePagerAdapter + 方向改变

Posted

技术标签:

【中文标题】ViewPager + FragmentStatePagerAdapter + 方向改变【英文标题】:ViewPager + FragmentStatePagerAdapter + orientation change 【发布时间】:2012-12-04 08:27:00 【问题描述】:

我有一个小问题:我有一个带有一些页面的 ViewPager,我使用 FragmentStatePagerAdapter 来处理数据。例如,在纵向中,ViewPager 有 20 页,而在横向中,ViewPager 只有 10 页。因此,在方向更改时,我创建了一个具有不同数据的新适配器。

这里稍微解释一下原因:我显示一张纵向图像和两张横向图像,但始终都是计数的。如果我有 10 张图片要展示,我有 10 张纵向和 5 张横向(总是两张)。

但现在我有一个奇怪的错误: 当我在索引 5 上的横向并转动设备时,ViewPager 的当前页面设置为 10。如果我再次将其转回,我在第 5 页。如果我现在将 ViewPage 滑动到第 10 页,适配器的 getItem 方法是从来没有打过电话,ViewPage 向我展示了一张纵向图片,而不是两张横向图片。 这怎么可能发生?适配器或 ViewPager 中是否有缓存?在 Activity 的 onCreate 中,一切都是新创建的,适配器以及 ViewPager 的数据(只是带有路径的字符串)。 那么知道如何解决这个非常可怕的“功能”吗?

这里有一些代码:

创建:

    mViewPagerAdapter = new ReaderPageViewAdapter(getSupportFragmentManager(), getBaseContext(), mCurrentDocument.mPages, getResources()
                .getConfiguration().orientation);
    mPageReader = (ReaderViewPager) findViewById(R.id.pager);
    mPageReader.setAdapter(mViewPagerAdapter);

适配器getItem:

    public Fragment getItem(final int index) 
        final PageInfo pageInfo = mPages.get(index);
        final PageFragment pageFragment = (PageFragment) PageFragment
                .instantiate(mContext, pageInfo.mClss.getName(), pageInfo.mArgs);
        return pageFragment;
    

如果您需要更多内容,请告诉我。谢谢

【问题讨论】:

对我来说,这种***.com/questions/17629463/… 方法非常适合! 【参考方案1】:

您可以覆盖 FragmentActivity onSaveInstanceState() 并且不在方法中调用 super.onSaveInstanceState()。

@Override
protected void onSaveInstanceState(final Bundle outState) 
    // super.onSaveInstanceState(outState);

不要使用 mViewPager.setSaveEnabled(false);

最终导致内存泄漏。每次改变方向后,它都会将 Fragments 放入 FragmentManager 的数组中,并且从不清理它。因此,在多次更改方向后,它的内存使用量会超过 100mb。我认为使用 onSaveInstanceState 方法是一种更好的方法。

【讨论】:

我必须验证 setSaveEnabled 是否导致我进行了 6 小时的内存泄漏调试。 抱歉这么晚才问,但你有没有发现 super.onSaveInstanceState(outState) 中的什么导致了这种意外行为?提前致谢 ! ;-) 是的,已经很晚了 :-) 在 onSaveInstanceState 中,它将片段保存在一个永远不会被清理的数组中。如果不调用 super,它不会将片段保存在此数组中。 @Informatic0re 我有查看寻呼机状态问题,但情况不一样。我的问题是here。我按照你的回答做了,但它不起作用。 也解决了我的问题。对于我的情况,这是关于 SO 的最有用的信息之一。非常感谢!【参考方案2】:

我也出现了这个问题,我找到原因了。

每次屏幕旋转,FragmentManager 将保留您所有活动托管的片段,它不会删除片段如果使用FragmentStatePagerAdapter,您可以使用FragmentManager.getFragments() 来检查片段的数量。

例子:activity有4个片段,经过4次方向改变,列表FragmentManager.getFragments()的大小将是20

我找到了一些解决方案:

    不要调用你的super.onSaveInstanceState() Activity,但这似乎不是一个好的解决方案,Fragment 无法保存状态和恢复。

    使用FragmentPagerAdapter 代替FragmentStatePagerAdapter。 但是方向改变后,ViewPager 托管的片段被空白(其他人有同样的问题吗?)。但是我可以删除Activity.onCreate 中的所有片段来修复它。像这样:

    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        FragmentManager fm = getSupportFragmentManager();
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null) 
            FragmentTransaction transaction = fm.beginTransaction();
            for (Fragment fragment : fragments) 
                transaction.detach(fragment).remove(fragment);
            
            transaction.commitNowAllowingStateLoss();
        
        ...
    

    但是Fragment.onCreateView() 调用了两次。

我仍在寻找完美的解决方案:D

编辑: 我终于解决了这个问题,这是因为我的 ViewPager 是在 onStart 之后添加的。当运行到 onStart 时,FragmentManager 将尝试恢复碎片状态。我追踪到FragmentManager,有这些代码:

com/android/support/support-fragment/24.2.1/support-fragment-24.2.1-sources.jar!/android/support/v4/app/FragmentManager.java

检查高亮行,f.mContainerId 实际上是我的 ViewPager id。然后它会尝试将片段视图添加到 ViewPager,在我的情况下, ViewPager 尚未添加,因此它将被空白,但片段状态为ATTACHED。而在FragmentPagerAdapter.instantiateItem(),如果添加了片段,它只是做attach片段,但片段已经附加,所以它什么都不做:(

我将 ViewPager 添加到活动布局 XML,它已修复。

编码愉快:D

【讨论】:

【参考方案3】:

您只需在 viewPager.setonpagechangelistener 中使用并实现要求代码应用您的应用程序,

http://developer.android.com/reference/android/support/v4/view/ViewPager.html

【讨论】:

我已经实现了 OnPageChangeListener 但我不想在那里完成所有工作。我认为只有一个缓存或我需要清除的东西。也许是 ViewPager 或 FragmentManager。适配器是全新创建的,ViewPage 是使用 findViewById 重新创建的,那么为什么要保存缓存呢?也许它是已保存状态,但我不知道如何删除它。

以上是关于ViewPager + FragmentStatePagerAdapter + 方向改变的主要内容,如果未能解决你的问题,请参考以下文章

ViewPager1嵌入ViewPager2,两者重叠,怎么禁止ViewPager1的滑动功能?

viewpager2的用法

andorid自己定义ViewPager之——子ViewPager滑到边缘后直接滑动父ViewPager

viewpager怎么实现画廊

在Viewpager中的一个Fragment中添加一个ViewPager

Viewpager嵌套Viewpager遇到的一些问题