it-swarm.com.ru

Фрагмент без представления падает при изменении конфигурации

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

Я решил, что смогу справиться с этим, используя тег <fragment /> для макета ландшафта, создавая фрагмент программно, если он не был запущен (в случае, когда мы находимся в портретной ориентации).

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

Java.lang.IllegalStateException: фрагмент не создал представление. на Android.app.Activity.onCreateView (Activity.Java:4095)

Документы для Fragment.isInLayout(), похоже, намекают на то, что он должен справиться с этим следующим образом:

Верните true, если макет включен как часть иерархии представления активности через тег. Это всегда будет верно, когда фрагменты создаются с помощью тега, за исключением случая, когда старый фрагмент восстанавливается из предыдущего состояния и не отображается в макете текущего состояния.

Так что вопрос в том, как сделать это правильно или я что-то упустил?

ОБНОВЛЕНИЕ:

Похоже, что isInLayout() ведет себя не так, как должно быть в настоящее время. Он возвращает false, если вы добавили Fragment в контейнер вручную.

Кроме того, если вы добавите Fragment вручную в контейнер, а затем поверните (устройство) к макету, который не содержит этого макета, произойдет сбой:

Вызывается: Java.lang.IllegalArgumentException: не найдено представление для идентификатора 0x7f060011 для фрагмента SearchFragment {4042f868 # 2 id = 0x7f060011 SearchFragment} в Android.app.FragmentManagerImpl.moveToState (FragmentManager.Java:722)

21
alexanderblom

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

Создайте две разные компоновки, одну в каталоге раскладок, другую в каталоге раскладок. Один из каталога layout-land будет использоваться в ландшафтном режиме. В качестве заполнителя, куда вы хотите поместить свой фрагмент, используйте элемент FrameLayout s и идентифицируйте его, скажем, с идентификатором "my_fragment". Макет в каталоге макета не должен содержать никаких элементов с таким идентификатором.

В вашем методе onCreate используйте findViewById (R.id.my_fragment), чтобы найти заполнитель фрагмента. Если он существует, вы находитесь в ландшафтном режиме и должны добавить свой фрагмент (если он еще не существует): add (R.id.my_fragment, new MyFragment, "myFragment). Если вы получаете значение null, вы находитесь в портретном режиме и должны не создавать фрагмент.

Будьте очень осторожны, чтобы никогда не заменять фрагмент, созданный с помощью тега, тем, который динамически создается в вашей программе. Фрагмент, для которого isInLayout возвращает true, это совершенно другой зверь, тот, для которого он возвращает false. Их жизненные циклы совершенно разные. Замена одного другим приведет к страшной проблеме IllegalStateException "фрагмент не создал представление".

-blake

22
Blake Meike

Ваша проблема также может быть связана с отсутствием макета Lanscape для фрагмента, который вы используете. У вас может быть один для портрета, и поэтому ваша программа работает нормально, но когда вы поворачиваете ваше устройство, ОС, вероятно, ищет представление в папке альбомной ориентации и не находит представление, поэтому объявляет его отсутствующим. Убедитесь, что у вас есть вид как в папке "layout", так и в layout-land.

0
Marco RS