2013-06-06 3 views
29

Я хочу осуществить это: enter image description here
Я использую ViewPager с FragmentStatePagerAdapter.
Я начал с примера с этой страницы:
http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.htmlКак уничтожить старые фрагменты в FragmentStatePagerAdapter

Это мой 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, это очень быстро увеличивает оперативную память.
Как удалить старые фрагменты?
Я также использовал это, но он ничего не делает:

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 секунды, а затем на следующем переключателе больше нет задержки.

Проверено на Nexus 7.

+0

У вас есть решение для этого? –

+0

, пожалуйста, предоставьте свое решение. @vovahost. – jyomin

ответ

12

Не следует мешать тому, как Android управляет вашими реализациями Fragment.Значение по умолчанию для setOffScreenPageLimit должно быть уже. Это означает, что Android будет уничтожать старые фрагменты, когда память будет работать медленно. Если у вас нет проблемы с памятью, просто оставьте ее.

Причина, по которой ваша память увеличивается, заключается в том, что Android хранит Fragment экземпляров в памяти, чтобы иметь возможность повторно подключаться к ним, а не создавать их. Я рекомендую вам учитывать непредвиденные ситуации, когда ваши Fragment экземпляры уничтожаются ОС, сохраняя их состояние, если это происходит, и пусть ОС выполняет свою работу.

Задержка, которую вы испытываете, может быть связана с некоторыми интенсивными вычислениями в потоке пользовательского интерфейса. Если это так, я предлагаю переместить это, например, на AsyncTask. Однако без кода это просто догадка о том, что может вызвать проблему. Но только начальная задержка предполагает, что вы загружаете что-то, что может блокировать поток пользовательского интерфейса.

Update: Посмотрите на https://stackoverflow.com/a/9646622/170781, который обрисовывает в общих чертах очень аккуратно, как ViewPager обрабатывает Fragment экземпляров.

+1

ohhh just setOffScreenPageLimite save me ... У меня была 4 вкладка фрагмента, когда я перемещаюсь с 1 на 4-й и 4-й на 1-й, удаляет все данные, но setOffscreenLimte восстанавливает это состояние. Спасибо lotttttttttttttttt ... – CoronaPintu

+0

Вы правы. Была некоторая проблема с вычислением в потоке пользовательского интерфейса – vovahost

+0

Рад, что я мог помочь! – Eric

3

FragmentStatePagerAdapter уже очень скудный с памятью, как он разрушает вашу ненужную fragments автоматически. Он просто сохраняет взгляды фрагментов прямо слева и справа от отображаемого в данный момент элемента и уничтожает остальные.

Пример: Итак, как только вы проведите в правильном направлении, он предварительно загружает скорострельный фрагмент справа и уничтожает фрагмент, который теперь является двумя слотами слева от текущего отображаемого фрагмента.

+1

. Кажется, что память всегда накапливается, что вы говорите, теоретически правильно, но не происходит. –

+0

вы загружаете 50-битные карты с 33k-модемом? :) Я никогда не видел такого поведения, когда я использую FSPA. – bofredo

+1

Я знаю, о чем я говорю, не волнуйтесь, вот несколько ссылок на код, которые я выложил, вы можете видеть, что ваша память накапливается. http://stackoverflow.com/questions/18241433/fragments-are-not-being-released-from-memory –

1

Я думаю, что проблема не в том, что ViewPager находится в ListFragments. Какой контент вы показываете на них? Вы выделяете много изображений? Можете ли вы опубликовать код своего списка?

Я бы предпочел сделать комментарий, но так как у меня недостаточно баллов, я надеюсь помочь, отредактировав этот ответ.

1

ViewPager сам имеет способ setOffscreenPageLimit, который позволяет указать количество страниц, поддерживаемых адаптером. Таким образом, ваши фрагменты, которые находятся далеко, будут уничтожены.

Немного сложно сказать, какова может быть ваша конкретная проблема, потому что я не знаю, что делает ваш фрагмент. По звуку 1-2-секундной задержки кажется, что вы можете немного поработать над потоком пользовательского интерфейса. И что еще вы делаете в своем фрагменте, потребляющем память? Возможно, вы загружаете изображения в некоторый статический кеш памяти и не освобождаете их от удаления фрагмента? Не могли бы вы предоставить код фрагмента, чтобы я мог видеть, что он делает?

В общем, я бы рекомендовал сбросить файл HPROF вашего приложения в тот момент, когда понадобилась дополнительная память, и проанализировать ссылки через MAT (инструмент анализатора памяти). У вас явно есть проблемы с утечкой памяти, и я очень сомневаюсь, что проблема заключается в том, что сами фрагменты не уничтожаются.

В случае, если вы не знаете, как анализировать кучу памяти, вот хороший video. Я не могу подсчитать, сколько раз это помогало мне идентифицировать и избавляться от утечек памяти в моих приложениях.

12

У меня была та же проблема. Но в моем случае ViewPager был внутри другого фрагмента. и после удаления ViewPagerFragment из FragmentManager все фрагменты из FragmentStatePagerAdapter остаются в менеджере фрагментов. поэтому после нескольких таких изменений это был OutOfMemoryError. Затем я переключаюсь на бревнах FragmentManager по:

FragmentManager.enableDebugLogging(true); 

И обнаружили, что идентификатор каждого нового inreases фрагмента каждый раз. Это происходит только с 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(); 

} 

В вашем случае. если вы не изменяете 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); 
    } 
} 
} 
+0

Где именно вы называете удаление экземпляров, созданных при помощи экземпляра, пожалуйста? –

+0

В onDetachMethod. – akelix

1

Переопределите это в 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(); 
} 
Смежные вопросы