如何在FragmentStatePagerAdapter中销毁旧片段

vov*_*ost 33 android android-fragments android-viewpager

我想实现这个: 在此输入图像描述
我使用带有FragmentStatePagerAdapter的ViewPager.
我从这个页面的示例开始:http:
//developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html

这是我的ViewPager适配器:

    public static class MyAdapter extends FragmentStatePagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        @Override
        public Fragment getItem(int position) {
            return ArrayListFragment.newInstance(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            super.destroyItem(container, position, object);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我的ViewPager的每个页面都包含一个带有一些数据的ListView.在我切换到ViewPager中的新页面时,它将非常快速地增加RAM内存.
我该如何删除旧碎片?
我也用过这个,但它什么也没做:

public void destroyItem(ViewGroup container, int position, Object object) {

    FragmentManager manager = ((Fragment) object).getFragmentManager();
    FragmentTransaction trans = manager.beginTransaction();
    trans.remove((Fragment) object);
    trans.commit();

    super.destroyItem(container, position, object);
}
Run Code Online (Sandbox Code Playgroud)

快速切换到新页面或旧页面后,还有1-2秒的延迟.有没有任何技术可以消除这种延迟.如果我切换到新页面并等待2秒钟,那么在下一次切换时不再有延迟.

在Nexus 7上测试过.

Eri*_*ric 14

您不应该试图干扰Android如何管理您的Fragment实施.setOffScreenPageLimit应该是一个默认值.这意味着Android会在内存不足时销毁旧片段.只要您没有内存问题,只需留下即可.

内存增加的原因是因为Android将Fragment实例保留在内存中以便能够重新连接到它们而不必实例化它们.我建议您考虑Fragment操作系统销毁实例的意外情况,如果发生这种情况则保存其状态,并让操作系统完成其工作.

您遇到的延迟可能是由于UI线程上的一些密集计算.如果是的话,我建议将其移到例如a AsyncTask.但是,如果没有代码,只需要猜测可能导致问题的原因.但是只有一个初始延迟表明你正在加载可能会阻止UI线程的东西.

更新:看看/sf/answers/675263571/,它非常巧妙地概述了ViewPager句柄Fragment实例的方式.


ake*_*lix 14

我有同样的问题.但在我看来,ViewPager是在另一个片段里面.从FragmentManager中删除ViewPagerFragment后,FragmentStatePagerAdapter中的所有片段都保留在片段管理器中.所以经过几次这样的改变就是OutOfMemoryError.然后我通过以下方式打开FragmentManager日志:

FragmentManager.enableDebugLogging(true);
Run Code Online (Sandbox Code Playgroud)

并且发现每个新片段的id每次都会复活.它只发生在StatePagerAdapter上.为了解决这个问题,我为每个即时片段调用了remove.

protected void dispatchOnDetach(Iterable<Fragment> fragments) {
    if (fragments == null)
        return;

    Activity aa = getActivity();
    if (aa == null)
        return;

    IBaseActivity ba = (IBaseActivity) aa;
    if (ba.isActivityStopped())
        return;

    FragmentManager frMan = ba.getSupportFragmentManager();
    FragmentTransaction frTr = frMan.beginTransaction();

    for (Fragment fr : fragments) {
        if (fr != null) {
            frTr.remove(fr);
        }
    }

    frTr.remove(this);
    frTr.commit();

}
Run Code Online (Sandbox Code Playgroud)

在你的情况下.如果您在运行时没有更改ViewPager,那么垃圾收集器即使在从片段管理器中删除之后也无法销毁您的片段,因为它们会引用它们.您应该检查一些全局类是否使用它们.

为了优化,您可以使用SoftReference或LruCache缓存每个瞬发片段.例:

public class MyAdapter extends FragmentStatePagerAdapter {

private final LruCache<Integer, Fragment> mCache;

public MyAdapter(FragmentManager fm) {
    super(fm);
    mCache = new LruCache<Integer, Fragment>(10);
}

@Override
public int getCount() {
    return NUM_ITEMS;
}

@Override
public Fragment getItem(int position) {
    return mCache.get(position);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
}

private class MyCache extends LruCache<Integer, Fragment> {

    public MyCache(int maxSize) {
        super(maxSize);
    }

    @Override
    protected Fragment create(Integer key) {
        return ArrayListFragment.newInstance(key);
    }
}
}
Run Code Online (Sandbox Code Playgroud)