如何销毁FragmentStatePagerAdapter中的旧片段

我想实现这个: 在这里输入图像说明
我使用带有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); } } 

我的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); } 

快速切换到新页面或旧页面后,也会有1-2秒的延迟。 有没有什么技术可以消除这个延迟。 如果我切换到一个新的页面,并等待2秒,然后在下一个开关没有更多的延迟。

testingNexus 7。

Solutions Collecting From Web of "如何销毁FragmentStatePagerAdapter中的旧片段"

你不应该试图干涉Android如何pipe理你的Fragment实现。 setOffScreenPageLimit的默认值应该是1。 这意味着Android会在内存不足的情况下销毁旧的碎片。 只要你没有记忆问题,就放手吧。

你的内存增加的原因是因为Android保持内存中的Fragment实例能够重新连接到他们,而不必实例化它们。 我build议你说明你的Fragment实例被操作系统销毁的意外情况,如果发生这种情况,可以节省他们的状态,让操作系统去做。

您遇到的延迟可能是由于UI线程上的一些密集计算。 如果是的话,我build议把它移出来,例如一个AsyncTask 。 但是,如果没有代码,只是猜测可能导致问题的原因。 但是只有最初的延迟表明你正在加载可能会阻塞UI线程的东西。

更新 :看看https://stackoverflow.com/a/9646622/170781 ,它非常整齐地概述ViewPager如何处理Fragment实例。

我有同样的问题。 但在我的情况下ViewPager是在另一个片段。 在从FragmentManager中移除ViewPagerFragment之后,FragmentStatePagerAdapter中的所有片段都停留在片段pipe理器中。 所以经过几次这样的更改,它是OutOfMemoryError。 然后我通过切换FragmentManager日志:

 FragmentManager.enableDebugLogging(true); 

并发现每一个新的片段的id每次都会发生。 它只发生在StatePagerAdapter中。 为了解决这个问题,我要求删除每个瞬间碎片。

 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(); } 

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

为了优化目的,您可以使用SoftReference或LruCache来caching每个瞬间片段。 例:

 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); } } } 

FragmentStatePagerAdapter已经非常节省内存,因为它会自动销毁不需要的fragments 。 它只是将碎片的视图直接保留在当前显示的项目的左侧和右侧,并破坏其他项目。

例如:所以一旦你滑动到正确的方向,它预加载了很快成为右邻居片段,并破坏当前显示的片段左侧的两个插槽的片段。

我认为这个问题不是在ListFragments上的ViewPager。 你对他们展示了什么样的内容? 你分配很多图像? 你可以发布你的ListFragment的代码?

我宁愿发表评论,但由于我没有足够的观点,我希望通过编辑这个答复来提供帮助。

ViewPager本身有一个方法setOffscreenPageLimit ,它允许你指定适配器保存的页面数量。 所以你们很远的碎片将被毁灭。

因为我不知道你的片段是干什么的,所以说你可能会遇到什么特别的问题有点难。 通过1-2秒的延迟声音,似乎你可能会在UI线程上做一些工作。 还有什么你在做你的片段是内存消耗? 也许你正在加载图像到一些静态的内存caching,并没有释放他们在片段删除? 你能否提供你的片段代码,所以我可以看看它在做什么?

一般来说,我会build议您将应用程序的HPROF文件倾销,因为它需要额外的内存,并通过MAT(内存分析工具)分析引用。 你显然有内存泄漏问题,我非常怀疑这个问题是在碎片本身不被破坏。

如果你不知道如何分析内存堆,这是一个很好的video 。 我无法计算它有多less次帮助我识别和摆脱我的应用程序中的内存泄漏。

在FragmentStatePagerAdapter中覆盖这个,注意到稍有变化。

 @Override public void destroyItem(ViewGroup container, int position, Object object) { if (position >= getCount()) { FragmentManager manager = ((Fragment) object).getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); trans.remove((Fragment) object); trans.commit(); }