Дилемма: когда использовать фрагменты против действий:

786

Я знаю, что Activitiesони предназначены для представления одного экрана моего приложения, в то время как Fragmentsони предназначены для многократного использования макетов пользовательского интерфейса со встроенной в них логикой.

Еще недавно я разработал приложение, в котором говорилось, что они должны быть разработаны. Я создал Activityдля представления экрана моего приложения и использовал фрагменты для ViewPagerили Google Maps. Я редко создавал ListFragmentили другой пользовательский интерфейс, который можно использовать несколько раз.

Недавно я наткнулся на проект, который содержит только 2 из них Activitiesодин SettingsActivityи другой MainActivity. Макет MainActivityзаполнен множеством скрытых фрагментов полноэкранного интерфейса, и отображается только один. В Activityлогике есть много FragmentTransitionsмежду различными экранами приложения.

Что мне понравилось в этом подходе, так это то, что, поскольку приложение использует ActionBar, оно остается неизменным и не перемещается с анимацией переключения экрана, как это происходит с Activityпереключением. Это дает более плавное ощущение этих переходов экрана.

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

ОБНОВЛЕНИЕ (01.05.2014): После этой презентации Эрика Бёрка из Square (я должен сказать, это отличная презентация с множеством полезных инструментов для разработчиков Android. И я никак не связан с Square)

http://www.infoq.com/presentations/Android-Design/

Исходя из моего личного опыта за последние несколько месяцев, я обнаружил, что лучший способ конструировать мои приложения - это создавать группы фрагментов, которые представляют поток в приложении и представляют все эти фрагменты в одном Activity. Таким образом, в основном у вас будет то же количество Activitiesв вашем приложении, что и количество потоков. Таким образом, панель действий остается неизменной на всех экранах потока, но воссоздается при изменении потока, что имеет большой смысл. Как утверждает Эрик Берк и, как я понял, философия использования как Activitiesможно меньшего числа людей не применима для всех ситуаций, потому что она создает беспорядок в том, что он называет «деятельностью Бога».

Эмиль Адз
источник

Ответы:

271

Эксперты скажут вам: «Когда я увижу пользовательский интерфейс, я буду знать, использовать ли Activityили Fragment». В начале это не будет иметь никакого смысла, но со временем вы действительно сможете сказать, если вам нужноFragment или нет.

Есть хорошая практика, которая мне очень помогла. Это произошло со мной, когда я пытался что-то объяснить моей дочери.

А именно, представьте себе коробку, которая представляет экран. Можете ли вы загрузить другой экран в этом окне? Если вы используете новый ящик, придется ли вам копировать несколько предметов из 1-го ящика? Если ответ Да, то вы должны использовать Fragments, потому что кореньActivity может содержать все дублированные элементы, чтобы сэкономить ваше время на их создание, и вы можете просто заменить части коробки.

Но не забывайте, что вам всегда нужен контейнерActivity ), иначе ваши детали будут рассеяны. Итак, одна коробка с деталями внутри.

Будьте осторожны, чтобы не использовать коробку неправильно. Эксперты по Android UX советуют (вы можете найти их на YouTube), когда нам следует явно загрузить другую Activity, вместо того, чтобы использовать Fragment(например, когда мы имеем дело с навигационным ящиком, у которого есть категории). Как только вы почувствуете себя комфортно Fragments, вы можете посмотреть все их видео. Еще больше они являются обязательным материалом.

Можете ли вы сейчас взглянуть на свой пользовательский интерфейс и выяснить, нужен ли вам Activityили Fragment? Вы получили новую перспективу? Я думаю, что ты сделал.

sandalone
источник
4
у вас есть ссылка на канал YouTube, который вы упомянули? Я ищу "Эксперты по Android UX" и "Android UX", но не совсем уверен, о каких видео вы говорите.
я--
2
Больше нет, смотрел это больше года назад. Поиск официального разработчика Android, говорящего о UX
sandalone
1
Один из примеров: активность имеет parentActivity, поэтому мы можем синтезировать backstack при входе из уведомлений, но я не думаю, что есть такой parentFragment.
fikr4n
@BornToCode есть getParentFragment: developer.android.com/reference/android/support/v4/app/...
ToolmakerSteve
@ToolmakerSteve да это getParentFragment, но это не то , что я имел в виду чувак см developer.android.com/guide/topics/manifest/...
fikr4n
129

Моя философия такова:

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

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

Это просто моя философия, так как фрагменты были введены.

VJ Vélan Solutions
источник
2
правда, но, как вы уже написали, иногда нужно использовать действия. Одним из примеров является экран камеры, где лучше использовать его в ландшафтном режиме. Другим примером является экран конфигурации, который отображается, когда вы помещаете настроенный виджет appWidget (на «рабочий стол» - приложение запуска).
Android-разработчик
Спасибо за ваш ответ и за то, что поделились своим опытом. Итак, вы считаете, что в Android-практике рекомендуется ограничивать приложение одним видом деятельности и использовать фрагмент для всего экрана, если архитектура приложения это позволяет?
Эмиль Адз
1
Тогда как вы решаете проблему фрагментов, нуждающихся в передаче друг другу «состояния»? Все состояния во всех ваших фрагментах должны жить в одном действии, в противном случае вы вынуждены использовать синглтон.
Mr_E
36
Я не уверен, что общаться между различными фрагментами гораздо проще, чем отправлять данные туда-сюда между действиями.
Денни
3
По крайней мере, onActivityResult()безопаснее и проще, чем обратные вызовы фрагментов.
CoolMind
59

Ну, согласно лекциям Google (может быть, здесь , я не помню), вы должны рассмотреть возможность использования фрагментов, когда это возможно, так как это делает ваш код легче поддерживать и контролировать.

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

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

Я создал пост об этой дилемме здесь , если вы хотите прочитать немного дальше.

разработчик Android
источник
5
Спасибо за ваш ответ и за то, что поделились своим опытом. Итак, вы считаете, что в Android-практике рекомендуется ограничивать приложение одним видом деятельности и использовать фрагмент для всего экрана, если архитектура приложения это позволяет?
Эмиль Адз
Это зависит от проекта, но если он слишком сложен для вас, вы также можете разделить несколько действий. Не бойтесь использовать любой из методов. Вы также можете использовать их обоих. Может быть, иногда вам будет слишком сложно использовать фрагменты вместо действий. Я думаю, что вы должны попытаться использовать фрагменты, но не заставляйте их быть повсюду, если они слишком мешают вам ...
Android-разработчик
Что делать, если я хочу, чтобы действие ActionBar оставалось неизменным, а весь контент переключался? Можно ли добиться этого с помощью мероприятий?
Эмиль Адз
27

Почему я предпочитаю Fragment, а не Activity во ВСЕХ СЛУЧАЯХ.

  • Деятельность дорогая. В Fragment представления и состояния свойств разделены - всякий раз, когда фрагмент находится в backstack, его представления будут уничтожены. Таким образом, вы можете сложить гораздо больше фрагментов, чем активность.

  • Backstackманипуляция. С помощью FragmentManagerнего легко очистить все фрагменты, вставить больше, чем фрагменты и т. Д. Но для Деятельности это будет кошмар, чтобы манипулировать этими вещами.

  • Очень предсказуемый жизненный цикл . Пока Хозяин Деятельность не переработан. Фрагменты в backstack не будут переработаны. Так что можно использовать, FragmentManager::getFragments()чтобы найти конкретный фрагмент (не рекомендуется).

Qylin
источник
Привет, я прочитал ваш отзыв о преимуществах Frag над Act. У вас есть какой-нибудь проект, чтобы показать то же самое в вашем Github Repo?
Уманг Бюрмон
24

Начиная с Jetpack , приложение Single-Activity является предпочтительной архитектурой. Особенно полезно с компонентом архитектуры навигации .

источник

Фрэнсис
источник
Спасибо тебе за это!
Симау Гарсия
1
Сегодня я впервые прочитал о Jetpack. :) Мы создаем отдельные приложения активности с момента появления фрагментов. Мульти активность намного сложнее.
Невероятный Янв
1
@TheincredibleJan Вы правы, архитектура приложения для единой деятельности была лучшим решением задолго до Jetpack
Фрэнсис
12

По моему это не очень актуально. Ключевым фактором для рассмотрения является

  1. как часто вы собираетесь повторно использовать части пользовательского интерфейса (например, меню),
  2. это приложение также для планшетов?

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

Исаак Урбина
источник
Я бы сказал, что основное использование фрагментов - создание пользовательских представлений, не думая о них как о пользовательских представлениях. это то, что происходит в любом случае. Фрагменты, которые мы изначально показывали в Google как удобный способ создавать приложения для планшетов, чтобы вы могли прикрепить их к различным действиям, если хотите. способ прикрепить код к представлению, более или менее, и сделать его закрепленным там, где вы хотите (без создания пользовательских представлений).
Ласси Киннунен,
11

Не забывайте, что действие - это блок / компонент приложения, которым можно поделиться и запустить через Intent! Таким образом, каждое действие в вашем приложении должно решать только одну задачу. Если у вас есть только одна задача в вашем приложении, я думаю, что вам нужно только одно действие и много фрагментов, если это необходимо. Конечно, вы можете повторно использовать фрагменты в будущих действиях, которые решают другие задачи. При таком подходе будет четкое и логичное разделение задач. И вам не нужно поддерживать одно действие с разными параметрами фильтра намерений для разных наборов фрагментов. Задачи определяются на этапе проектирования процесса разработки на основе требований.

гость
источник
В наших приложениях одной из задач является удержание навигационной панели для ввода различных фрагментов. :) Почему я должен бороться с намерениями для фрагментов? Понятно и логично хранить статическую ссылку на «глобальный» класс данных для глобальных данных и передавать некоторые значения методу создания экземпляра фрагмента.
Невероятный Янв
9

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

** Начните новое действие только в том случае, если имеет смысл одновременно открывать основное и это действие (подумайте о нескольких окнах).

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

TheHebrewHammer
источник
Re "Начните новое действие, только если имеет смысл одновременно открывать основное и это действие (подумайте о нескольких окнах)". Я так не думаю. Эта ситуация хорошо решается с помощью фрагментов attach / detachметодов.
ToolmakerSteve
7

Что я и сделал: используя меньше фрагментов, когда это возможно. К сожалению, это возможно почти в любом случае. Итак, я получаю много фрагментов и немного активности. Некоторые недостатки я понял:

  • ActionBar & Меню: когда 2 фрагмента имеют разные названия, меню, что
    будет трудно обрабатывать. Пример: при добавлении нового фрагмента вы можете изменить заголовок панели действий, но при его извлечении изbackstack извлечении невозможно восстановить старый заголовок. Вам может понадобиться Панель инструментов в каждом фрагменте для этого случая, но, поверьте мне, это потратит вас больше времени.
  • Когда нам нужно startForResult , у активности есть, а у фрагмента нет.
  • Не имеет анимации перехода по умолчанию

Мое решение для этого - использовать Activity, чтобы обернуть фрагмент внутри. Таким образом, у нас есть отдельная панель действий, меню startActivityForResult, анимация, ...

Я люблю кодировать
источник
1
Очень полезные замечания, спасибо. Можете ли вы уточнить « Деятельность, чтобы обернуть фрагмент »? Вы делали отдельную активность для каждого фрагмента? Если так, вам нужен фрагмент вообще?
ToolmakerSteve
3
есть способ восстановить заголовок и прочее. используйте, getSupportFragmentManager().addOnBackStackChangedListenerчтобы добавить слушателя. получить текущий фрагмент в этом слушателе, а затем установить заголовок и прочее.
Бабай
4

Одно большое преимущество fragmentизбыточной активности состоит в том, что код, который используется для фрагмента, может использоваться для различных действий. Таким образом, он обеспечивает возможность повторного использования кода при разработке приложений.

Санчит Бхасин
источник
3
Как? Не могли бы вы привести пример, пожалуйста?
sofs1
1
@ sofs1 Ваш вопрос не имеет особого смысла. Любой код во фрагменте остается неизменным, независимо от того, из какой активности установлен фрагмент.
Невероятный Янв
@TheincredibleJan Но разве мы не могли бы сказать: «Любой код в действии остается неизменным независимо от того, из какого действия создается второе действие»? Я не вижу разницы.
iforce2d
3

использовать одну активность для каждого приложения , чтобы обеспечить основу для fragment использования fragmentна экран, fragmentsявляются облегченным весом , по сравнению с activites фрагментами являются многоразовыми фрагменты лучше подходит для приложений , которые поддерживают как телефон & таблетку

Варг
источник
2

Вы можете использовать один из них.
По сути, вы должны оценить, какой из них является лучшим для вашего приложения. Подумайте, как вы будете управлять бизнес-потоком и как хранить / управлять настройками данных.

Подумайте, как фрагменты хранят данные мусора. Когда вы реализуете фрагмент, у вас есть корень активности для заполнения фрагментом (ами). Таким образом, если вы пытаетесь реализовать много действий со слишком большим количеством фрагментов, вы должны учитывать производительность своего приложения, поскольку вы управляете (грубо говоря) двумя жизненными циклами контекста, помните о сложности.

Помните: я должен использовать фрагменты? Почему я не должен?

С уважением.

Франклин Хирата
источник
1

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

if (id == R.id.forecast) {

    ForecastFragment forecastFragment = new ForecastFragment();
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.main_content, forecastFragment);
    ft.addToBackStack("backstack");
    forecastFragment.setArguments(b);
    ft.commit();
}

Таким образом, пользователю не нужно будет переходить в другой вид деятельности.

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

Тео
источник
Что делает этот пример лучшим пользовательским опытом? Как они будут знать (или заботиться), что они делают деятельность или фрагмент?
iforce2d
1

Это зависит от того, что вы хотите построить на самом деле. Например navigation drawerиспользует фрагменты. Вкладки использовать fragmentsтакже. Еще одна хорошая реализация, где у вас есть listview. Когда вы поворачиваете телефон и щелкаете строку, активность отображается на оставшейся половине экрана. Лично я использую fragmentsи fragment dialogs, как это более профессионально. Кроме того, они обрабатываются легче во вращении.

Тео
источник