ViewPager与肖像和风景的不同适配器

时间:2014-04-18 07:51:33

标签: android android-viewpager orientation-changes fragmentstatepageradapter

在纵向模式下,我的ViewPager有3个片段A,B,C,但在横向模式下,它只有2个片段A和C.所以我为每个模式创建了2 FragmentStatePagerAdapter个。问题是当屏幕方向改变时,ViewPager恢复并使用旧方向的先前片段。例如,当从纵向更改方向到横向时,ViewPager现在显示2个片段A,B而不是A和C.我知道为什么会发生这种情况,但无法为此找到一个好的解决方案。

我目前的解决方法是为ViewPager使用不同的ID(例如:id / viewpager_portrait用于纵向,id / viewpager_landscape用于横向布局)以防止重复使用片段但这会导致内存泄漏,因为旧片段不会被摧毁,仍然留在记忆中。

我尝试了一些解决方法,例如在活动的onCreate中调用super.onCreate(null),或者删除活动ViewPageronSaveInstanceState的片段,但它们都会导致我的应用崩溃。

所以我的问题是当方向改变时如何避免在FragmentStatePagerAdapter中重复使用一个或多个片段?

任何帮助将不胜感激。提前谢谢。

4 个答案:

答案 0 :(得分:3)

问题可能是Android提供的PagerAdapter的内置Fragment实现假设项目将保持不变,因此保留并重用所有{{1}的基于索引的引用添加到Fragment的s。即使在由于配置更改或进程被终止而重新创建ViewPager(和FragmentManager s)之后,这些引用也会通过Activity进行维护。

您需要做的是编写自己的Fragment实现,将自定义标记与每个PagerAdapter相关联,并将Fragment存储在基于标记的内容中(而不是索引)基于)格式。在添加抽象方法以基于索引和Fragment方法提供标记之后,您可以从现有方法中派生出一个通用实现。当然,您必须从getItem()删除先前配置中添加的孤立/未使用的Fragment(理想情况下保持其状态)。

如果您不想自己实现整个解决方案,那么CWAC-Pager库中的ViewPager可以用来轻松地提供合理的实现。初始化后,您可以根据它提供的标记分离相关的ArrayPagerAdapter,并根据需要从适配器中删除/添加它。

答案 1 :(得分:1)

覆盖适配器中的getItemPosition()并返回POSITION_NONE。因此,当重新创建ViewPager时,它会调用getItemPosition(),因为您已从此处返回POSITION_NONE,它将调用getItem()。您应该从此getItem()返回新的片段。参考:http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getItemPosition%28java.lang.Object%29

答案 2 :(得分:1)

为什么在你的方向发生变化时只需删除片段B,就可以为viewpager使用两个不同的ID?

您可以像这样在onCreateView()或onResume()中检索您的片段(此示例在父片段内部工作,但也可以在onResume()中的父活动中使用):

@Override
public void onResume() {
    super.onResume();

    // ... initialize components, etc.

    pager.setAdapter(pagerAdapter);

    List<Fragment> children = getChildFragmentManager().getFragments();

    if (children != null) {
        pagerAdapter.restoreFragments(children, orientation);
    }
}

然后在适配器内:

@Override
public void restoreFragments(List<Fragment> fragments, int orientation) {
    List<Fragment> fragmentsToAdd = new ArrayList<Fragment>();
    Collections.fill(fragmentsToAdd, null);
    if (Configuration.ORIENTATION_LANDSCAPE == orientation) {
        for (Fragment f : fragments) {
            if (!(f instanceof FragmentB)) {
                fragmentsToAdd.add(f);
            }
        }
    }
    this.fragmentsInAdapter = Arrays.copyOf(temp.toArray(new Fragment[0]), this.fragments.length); // array of all your fragments in your adapter (always refresh them, when config changes, else you have old references in your array!
    notifyDataSetChanged(); // notify, to remove FragmentB
}

这应该有效。

顺便说一下。如果您使用支持库V13,则无法使用FragmentManager.getFragments(),因此您需要通过id或tag获取它们。

答案 3 :(得分:1)

在您的Activity中覆盖OnConfigurationChanged()(也为您在Manifest中的活动添加android:configChanges =“orientation”),这样您可以手动管理方向更改。现在,您需要做的就是在OnOrientaionChanged中更改适配器(同时跟踪当前位置)。这样你就可以使用单个布局,一个ViewPager,而且你不必担心片段没有被回收(好吧,你将有很多工作来弥补)。 祝你好运!