我在ViewPager
和Fragment
的实例中遇到了一些问题。
我有一个ViewPager
(让我们称之为父亲)有4个片段,在最后一个片段中我有另一个ViewPager
(并称之为Child),其中包含动态片段数量。我的意思是我根据内存中的对象列表创建Child。因此,如果列表包含3个objets,则Child将在其中包含3个片段。如果在确定的时刻发生了某些事情,并且我得到一个包含1个对象的列表,那么我必须用1个片段更新Child。这里的一个重点是每个Child的Fragment
在返回的列表中都有自己的对象,并且是基于这个对象创建的。
我将片段列表设置为子ViewPager
的代码如下:
@Override
public void setViewPagerChildFragments(List<Fragment> fragments) {
if (fragments != null) {
DefaultStateViewPagerAdapter adapter = (DefaultStateViewPagerAdapter) mViewpagerChild.getAdapter();
if (adapter == null) {
/* In this case I use getChildFragmentManager() because
it's inside the last fragment of the ViewPager Father*/
adapter = new DefaultStateViewPagerAdapter(getChildFragmentManager(), fragments);
mViewpagerChild.setAdapter(adapter);
} else {
adapter.setFragments(fragments); // Into this method I do notifyDataSetChanged() already
}
}
}
请注意,我尝试使用相同的适配器实例来设置片段,然后通知更改(notifyDataSetChanged()
在方法内)。如果我没有得到适配器的实例,我会创建一个新实例并将其设置为ViewPager
子项。
问题发生了,例如,当我将ViewPager
Child设置为2个片段时,稍后我需要将其设置为1个片段。 ViewPager
只显示其中的一个片段,但第二个片段仍然附着且未被销毁。我知道这是因为我做了一个调用getChildFragmentManager().getFragments()
的测试,我可以看到应该被销毁的片段仍在那里。
您可能会说这实际上不是问题,因为Garbage Collector
可以删除未使用的Fragment
。但是,如果在某个时刻,例如,我尝试再次将2个新片段设置到ViewPager
子节点中,它会使用未使用的Fragment
实例而不是创建新实例,不幸的是它也会使用相同的对象,而不是新的。
这是我的DefaultStateViewPagerAdapter
代码:
public class DefaultStateViewPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Fragment> mFragments;
private ArrayList<String> mFragmentTitles;
public DefaultStateViewPagerAdapter(FragmentManager fm) {
super(fm);
this.mFragments = new ArrayList<>();
this.mFragmentTitles = new ArrayList<>();
}
public DefaultStateViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.mFragments = (ArrayList<Fragment>) fragments;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getItemPosition(Object object) {
int index = mFragments.indexOf(object);
if (index < 0) {
index = POSITION_NONE;
}
return index;
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
public void clearFragments() {
mFragments.clear();
mFragmentTitles.clear();
}
public void setFragments(List<Fragment> fragments) {
mFragments = (ArrayList<Fragment>) fragments;
notifyDataSetChanged();
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitles.add(title);
}
}
我已经尝试覆盖saveState
以避免ViewPager
使用旧片段的实例,例如:
@Override
public Parcelable saveState() {
return null;
}
虽然有效,但ViewPager
不再使用旧引用,但仍未附加未使用的Fragment
,这会导致内存泄漏。
我不知道为什么即使我设置了新的适配器后ViewPager
也没有破坏它的碎片。有没有人遇到过这个问题?
答案 0 :(得分:0)
我找到了解决方案。
解决方案非常简单。我只需要手动设置null
到Child的适配器。有了这个,ViewPager
被迫摧毁每个片段。
因此,在onDestroyView
的父亲的Fragment
中,我添加了:
@Override
public void onDestroyView() {
super.onDestroyView();
mViewpagerChild.removeOnPageChangeListener(mOnPaymentMethodsPageChangeListener);
mViewpagerChild.setAdapter(null); // <-- This is what I added
}