Можно ли создавать и обрабатывать элементы действий на панели действий с помощью фрагментов?

Фон

У меня есть аналогичный сценарий, показанный на примере веб-сайта Android о фрагментах (ссылка здесь) :

  • маленький экран, книжная ориентация: одна панель
  • маленький экран, альбомная ориентация: одна панель
  • 7-дюймовый планшет, книжная ориентация: одна панель
  • 7-дюймовый планшет, альбомная ориентация: двойная панель, широкий
  • 10-дюймовый планшет, книжная ориентация: двойная панель, узкий
  • Планшет 10", альбомная ориентация: двойная панель, широкий
  • ТВ, альбомная ориентация: двойное стекло, широкое

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

Эта проблема

Следующий сценарий очень странный:

  • Устройство имеет одну панель для книжной ориентации и 2 панели для альбомной ориентации.

  • Оба моих фрагмента создают свои собственные элементы панели действий.

  • Переключение с книжной на альбомную показывает все элементы действия (это то, что я хочу)

  • При переключении с ландшафта на портрет отображаются все элементы действия.

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

Что я пробовал

Я пытался вызвать invalidateOptionsMenu() для действия, которое содержит оба фрагмента, но это не помогло.

Я также добавил следующий код для каждого из фрагментов, и он отлично работает:

@Override
public void onStart() {
    super.onStart();
    setHasOptionsMenu(true);
}

@Override
public void onStop() {
    super.onStop();
    setHasOptionsMenu(false);
}

Вопрос

Почему это происходит?

Является ли мое решение включения/отключения optionsMenu (таким образом, включение/отключение создания элементов панели действий фрагментами) жизнеспособным решением? Есть ли лучшее решение?

Хорошо ли вообще, чтобы фрагменты обрабатывали элементы действий?


person android developer    schedule 20.03.2013    source источник


Ответы (2)


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

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

Тем не менее, я не вижу ничего плохого в вашем текущем решении.

person j__m    schedule 20.03.2013
comment
но почему фрагменты все еще существуют в менеджере фрагментов? возможно ли, что он кэширует их, чтобы повторно использовать? пример кода показывает, что для проверки его существования он ищет его как представление, а не как фрагмент. это очень странно. - person android developer; 20.03.2013
comment
Фрагменты фактически уничтожаются (если вы не вызываете setRetainInstance), но диспетчер фрагментов сохраняет свой список фрагментов как состояние, которое восстанавливается при воссоздании действия. Помните, что, согласно документации Android, фрагмент вообще не обязан иметь какой-либо пользовательский интерфейс. onCreateView может возвращать значение null, если вы создаете фрагмент вручную с помощью FragmentTransaction, а не размещаете его в своем макете. С другой стороны, если фрагмент находится в вашем макете, а onCreateView возвращает значение null, родительское представление вызовет исключение NullPointerException. - person j__m; 20.03.2013
comment
Итак, если и только если я помещу фрагмент в файл макета (xml), даже если у меня есть несколько макетов, по одному для каждой ориентации, фрагмент останется навсегда? зачем ему заново создавать меню, если оно даже не отображается? - person android developer; 20.03.2013
comment
нет, диспетчер фрагментов воссоздает все активные фрагменты независимо от того, находятся они в макете или нет. когда макет раздут, onCreateView() будет вызываться для загруженного фрагмента, который соответствует идентификатору, указанному в макете; если такого фрагмента нет (поскольку ваша активность не восстанавливает предыдущее состояние), то создается фрагмент, указанный вами в макете. - person j__m; 20.03.2013
comment
Помните, что фрагменту не обязательно иметь пользовательский интерфейс. Когда ваша активность разрывается, диспетчер фрагментов не ищет в иерархии представлений, чтобы увидеть, есть ли у фрагмента пользовательский интерфейс, не записывает, есть ли у фрагмента пользовательский интерфейс или нет, и когда активность воссоздается, не условно воссоздает фрагмент на основе от того, есть ли он в макете или нет. Диспетчер фрагментов ничего из этого не делает. Каждый фрагмент в диспетчере фрагментов воссоздается при воссоздании действия. - person j__m; 20.03.2013
comment
Итак, я вернулся к первоначальному вопросу: почему он снова вызвал onCreateOptionsMenu? почему он был создан, хотя getActivity вернул бы значение null, если бы я использовал его, когда щелкнул один из элементов действия? - person android developer; 21.03.2013
comment
Что вы ищете, обоснование? Я не думаю, что есть какая-то веская причина для такого поведения. Я объяснил, как это работает. Диспетчер фрагментов безоговорочно воссоздает каждый фрагмент, и точка. У него нет никакого ума. Я сомневаюсь, что кто-либо в команде Android задумывался о том, что может произойти, если фрагмент добавляет элементы панели действий, а затем исчезает из макета во время изменения конфигурации. Мы просто должны работать с этим, как есть. - person j__m; 21.03.2013
comment
пожалуйста, не сердитесь. это то, что я искал, объяснение того, что происходит (даже без всего, что связано с панелью действий). - person android developer; 21.03.2013

Вы можете в методе onPrepareOptionsMenu(..) правого фрагмента скрывать и отображать пункты меню по мере необходимости, просматривая Configuration, получаемый из getResources().getConfiguration().

Как говорится в другом ответе, обычно нежелательно изменять количество фрагментов, отображаемых во время выполнения - мое приложение делало это, и я столкнулся с тысячами проблем.

person Alex Curran    schedule 20.03.2013
comment
Если я полагаюсь на конфигурацию, это означает, что фрагмент предполагает, что он всегда будет существовать только в определенных случаях. - person android developer; 20.03.2013
comment
В моем подходе конфигурация используется только для проверки того, следует ли загружать меню, а не существует фрагмент или нет. - person Alex Curran; 21.03.2013
comment
но если элементы действия связаны только с фрагментом, вы захотите показать их, только если фрагмент показан пользователю (конечно, в случае, если это фрагмент пользовательского интерфейса). - person android developer; 21.03.2013