在纵向模式下,我的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),或者删除活动ViewPager
中onSaveInstanceState
的片段,但它们都会导致我的应用崩溃。
所以我的问题是当方向改变时如何避免在FragmentStatePagerAdapter
中重复使用一个或多个片段?
任何帮助将不胜感激。提前谢谢。
答案 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,而且你不必担心片段没有被回收(好吧,你将有很多工作来弥补)。 祝你好运!