Фрагмент-должен ли я повторно использовать представление в onCreateView и как это сделать?

На самом деле, я всегда повторно использовал свой взгляд в своих фрагментах следующим образом:

private View mView = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (mView == null)
        mView = inflater.inflate(R.layout.view);
    return mView;
}

это работает, с viewpager и так далее. Теперь я начал использовать свои фрагменты в простых действиях, и если, и только если я добавлю фрагмент в backstack, это не удастся из-за java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

Итак, мои вопросы:

  • все в порядке, если я проверю родительские представления, удалите его и добавьте в новый родитель?
  • или я должен всегда воссоздать целях и никогда не использовать его? Если да, то почему?
  • есть ли другие точки, где повторное использование представления не удастся?

3 ответов


возможно, это может помочь понять поведение. Если вы проверить FragmentManagerImpl.java вы найдете следующее:

Сначала мы создаем представление, вызывая onCreateView() (строка 845), а затем мы обертываем созданный вид другим видом, который становится родителем нашего представления (строки 848-849). Это означает, что наше представление не становится дочерним для реального контейнера, но теперь оно является дочерним для представления оболочки. Проблема с повторным использованием происходит, когда вид получает извлекается из контейнера (строке 998). FragmentManager удаляет представление обертки из контейнера, но наше реальное представление остается добавленным к родительскому представлению обертки. Это то, что вызывает проблему, которую вы испытываете.

таким образом, если вы удалите представление из родительского, оно может работать. Даже зная это, я бы не рекомендовал повторно использовать представления во фрагменте также потому, что представления могут жить немного дольше, чем фрагменты, потому что их можно использовать в" исчезающих " анимациях даже после фрагмента уничтожен. Если вы попытаетесь удалить такое представление из его родителя в то время, анимация может быть нарушена.

еще один аргумент, чтобы не кэшировать представление, заключается в том, что Android не поддерживает переработку представления в фрагментах по дизайну. Помни!--1--> позволяющий использовать мнения? Android заботится о кэшировании и правильном повторном использовании этих представлений. Однако это не относится к фрагменту.


в настоящее время я повторно использую представление с чем-то вроде этого:

if(view == null){
    view = (ViewGroup) inflater.inflate(R.layout.news_list, container, false);
} else {
    ((ViewGroup) view.getParent()).removeView(view);
}
return view;

Я не знаю, правильно ли это, но, похоже, это работает для меня..

примечание: Я использую этот aproach, потому что у меня есть listview во фрагменте, и когда пользователь нажимает на элемент, он загружает новый фрагмент (диспетчер фрагментов заменяет текущий фрагмент списка). Затем, когда пользователь нажимает кнопку backbutton, так как я повторно использую тот же старый вид фрагмента (который не уничтожается при удалении с FM), то пользователь продолжает просмотр списка в том положении, в котором он был до открытия вида фрагмента детали.


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

1.Текущий фрагмент onCreateView был вызван в первый раз. Кэшируя, как указано выше, мы будем раздувать целевой макет (этот макет, включая тег фрагмента). 2.By inflater.inflate это сделает фрагмент вставки, добавленный в макет правильно,onCreateView будет называться. 3.Когда текущий фрагмент должен быть уничтожен, фрагмент вставки onDestroyView будет называться правильно.

4.Когда текущий фрагмент onCreateView вызывается снова, мы возвращаем кэшированное представление, не вызывая inflater.inflate. Вы найдете фрагмент вставки onCreateView и onDestroyView или другие методы жизненного цикла не будут вызваны.

это все, что я хочу отметить.