我在使用 ViewPager
和 Fragment
的实例时遇到了一些问题。
我有一个包含 4 个 fragment 的 ViewPager
(我们称其为父亲),在最后一个 fragment 中我有另一个具有动态 fragment 数量的 ViewPager
(并将其称为子 fragment )。我的意思是我根据内存中的对象列表创建子对象。因此,如果列表包含 3 个对象,则 Child 将在其中包含 3 个 fragment 。如果在确定的时刻发生了某些事情并且我得到了一个包含 1 个对象的列表,那么我必须只用 1 个 fragment 更新 Child。这里的重点是每个 Child 的 Fragment
从返回的列表中都有自己的对象,并基于该对象创建。
我将 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
}
}
}
请注意,我尝试使用相同的适配器实例来设置 fragment ,然后通知更改(notifyDataSetChanged()
在方法内部)。如果我没有获得适配器的实例,我将创建一个新实例并将其设置为 ViewPager
子项。
问题发生了,例如,当我用 2 个 fragment 设置 ViewPager
子级时,过了一会儿我需要用 1 个 fragment 设置它。 ViewPager
仅显示其中的 1 个 fragment ,但第二个 fragment 仍附加且未被破坏。我知道它是因为我做了一个调用 getChildFragmentManager().getFragments()
的测试,我可以看到应该被销毁的 fragment 仍然存在。
您可能会说这实际上不是问题,因为垃圾收集器
可以删除未使用的 fragment
。但是,例如,如果在某个时刻,我尝试再次将 2 个新 fragment 设置到 ViewPager
子对象中,它会使用未使用的 Fragment
实例而不是创建一个新 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
使用旧 fragment 的实例,例如:
@Override
public Parcelable saveState() {
return null;
}
成功了,ViewPager
不再使用旧的引用,但未使用的 Fragment
仍然存在,这会导致内存泄漏。
我不知道为什么 ViewPager
即使在我设置了新的适配器后也没有销毁它的 fragment 。有没有人遇到过这个问题?
最佳答案
我找到了解决方案。
解决方法很简单。我只需要手动将 null
设置为子适配器。这样,ViewPager
就被迫销毁每个 fragment 。
所以我在 Fragment
的父亲的 onDestroyView
中添加了:
@Override
public void onDestroyView() {
super.onDestroyView();
mViewpagerChild.removeOnPageChangeListener(mOnPaymentMethodsPageChangeListener);
mViewpagerChild.setAdapter(null); // <-- This is what I added
}
关于android - 即使在设置新适配器后,ViewPager 仍保留 fragment 的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45761076/