Фрагмент-должен ли я повторно использовать представление в 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
или другие методы жизненного цикла не будут вызваны.
это все, что я хочу отметить.