即使在设置新的适配器

时间:2017-08-18 16:21:53

标签: android android-fragments android-viewpager fragmentstatepageradapter

我在ViewPagerFragment的实例中遇到了一些问题。

我有一个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也没有破坏它的碎片。有没有人遇到过这个问题?

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。

解决方案非常简单。我只需要手动设置null到Child的适配器。有了这个,ViewPager被迫摧毁每个片段。

因此,在onDestroyView的父亲的Fragment中,我添加了:

@Override
public void onDestroyView() {
    super.onDestroyView();
    mViewpagerChild.removeOnPageChangeListener(mOnPaymentMethodsPageChangeListener);
    mViewpagerChild.setAdapter(null); // <-- This is what I added
}