Фрагмент без представления падает при изменении конфигурации - PullRequest
21 голосов
/ 08 февраля 2011

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

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

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

java.lang.IllegalStateException: фрагмент не создал представление.atroid.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)

Ответы [ 2 ]

22 голосов
/ 06 апреля 2011

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

Создайте два разных макета, один в каталоге макетов, другой в каталоге layout-land.Один из каталога 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 «Fragment is not view».

-blake

0 голосов
/ 04 января 2012

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

...