Как сделать фрагмент в android studio

Обновлено: 06.07.2024

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

Фрагменты представляют как бы часть пользовательского интерфейса Activity. Фрагменты можно многократно использовать и как в одном Activity, так и подключать их в различные Ac tivity. Кроме того, их можно подключать и удалять с экрана даже прямо во время работы приложения. Например, если вы зададите некоторые объекты на экране (кнопки, переключатели и т.д.), то во время работы приложения вы не сможете их скрыть, это можно сделать только при редактировании файла layout. Используя же фрагменты, можно с помощью заданных кнопок в любое время добавлять или убирать дополнительные объекты пользовательского интерфейса, определенные вами в фрагментах.

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

Перейдем от теории к практике. Создаем новый проект, названия по умолчанию, берем Blank Activity. Сначала давайте зайдем в activity_main.xml и добавим следующие элементы:

Интерфейс примет вид:


Мы настроили внешний вид нашего Activity, как мы это делаем обычно. Но теперь давайте поделим этот вид на отдельные 3 вида.

В папке layout приложения создаем файл fragment1.xml и добавим в него только две первых кнопки:

Создаем в этой же папке еще один файл fragment2.xml и добавляем в него два переключателя:

И еще 1 файл fragment3.xml:

Теперь примемся за создание самих фрагментов, они имеют расширение java. В папке, хранящей файл MainActivity.java создаем новый пакет с именем fragments:



В этом пакете fragments создаем 3 файла java класса: fragment1, fragment2, fragment3:



Теперь возьмемся за редактирование созданных классов фрагментов. Открываем файл fragment1.java. Чтобы наше приложение с фрагментами работало и на более старых версиях ОС Android, добавим в импорт классов фрагментов строку:

Добавим в файл fragment1.java наследование класса Fragment, вместо метода onCreate в этом случае используют onCreateView, зададим внешний вид класса с созданного раньше layout - файла fragment1.xml :

Открываем файл fragment2 и делаем аналогично:

Ну и класс fragment3:

Все, фрагменты созданы. Давайте теперь отредактируем файл activity_main.xml, используя созданные фрагменты. Добавляем в activity_main.xml следующий код:

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


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

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

Я видел две общие практики для создания нового фрагмента в приложении:

Второй вариант использует статический метод newInstance() и обычно содержит следующий метод.

Сначала я подумал, что основным преимуществом является то, что я могу перегрузить метод newInstance(), чтобы обеспечить гибкость при создании новых экземпляров фрагмента, но я мог бы также сделать это, создав перегруженный конструктор для фрагмента.

Я что-то пропустил?

Каковы преимущества одного подхода над другим? Или это просто хорошая практика?

ОТВЕТЫ

Ответ 1

Если Android решает снова создать свой фрагмент, он будет вызывать конструктор без аргументов вашего фрагмента. Поэтому перегрузка конструктора не является решением.

С учетом сказанного, способ передать материал вашему фрагменту, чтобы они были доступны после воссоздания Фрагмента Android, - передать пакет методу setArguments .

Итак, например, если мы хотим передать целое число в фрагмент, мы будем использовать что-то вроде:

И позже в фрагменте onCreate() вы можете получить доступ к этому целому числу, используя:

Этот пакет будет доступен, даже если Fragment каким-то образом воссоздается Android.

Также обратите внимание: setArguments может быть вызван только до того, как Фрагмент будет прикреплен к Activity.

Ответ 2

Единственное преимущество использования newInstance() , которое я вижу, следующее:

У вас будет одно место, где все аргументы, используемые фрагментом, могут быть объединены, и вам не нужно писать код ниже каждый раз, когда вы создаете фрагмент.

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

Итак, я считаю, что использование статического newInstance() для создания экземпляра является хорошей практикой.

Ответ 3

Существует и другой способ:

Ответ 4

Хотя @yydl дает вескую причину, почему лучше использовать метод newInstance :

Если Android решает воссоздать ваш фрагмент позже, он будет звонить конструктор без аргументов вашего фрагмента. Поэтому перегрузка конструктор не является решением.

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

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

В течение жизни Activity фрагмент создается, как указано выше, и неоднократно уничтожается Android. Это означает, что если вы поместите данные в сам объект фрагмента, он будет потерян после уничтожения фрагмента.

Чтобы обходной путь, андроид просит сохранить данные с помощью Bundle (вызов setArguments() ), к которому затем можно получить доступ из YourFragment . Аргумент Bundle защищен Android, и, следовательно, гарантируется постоянный.

Один из способов установки этого пакета - использовать статический метод newInstance :

может делать то же самое, что и метод newInstance .

Естественно, это не удастся, и это одна из причин, по которой Android хочет использовать метод newInstance :

Как дополнительное объяснение, здесь Android Fragment Class:

Обратите внимание, что Android запрашивает, чтобы аргументы были установлены только при построении, и гарантирует, что они будут сохранены.

EDIT. Как указано в комментариях @JHH, если вы предоставляете настраиваемый конструктор, который требует некоторых аргументов, то Java не предоставит вашему фрагменту конструктор default arg. Таким образом, вам потребуется определить конструктор no arg, который можно избежать с помощью метода newInstance factory.

EDIT: Android не позволяет больше использовать перегруженный конструктор для фрагментов. Вы должны использовать метод newInstance .

Ответ 5

Я не согласен с yydi ответ, говоря:

Если Android решает воссоздать ваш фрагмент позже, он будет звонить конструктор без аргументов вашего фрагмента. Поэтому перегрузка конструктор не является решением.

Я думаю, что это решение и хорошее, это именно та причина, по которой он был разработан основным языком Java.

Истинно, что система Android может уничтожить и воссоздать ваш Fragment . Итак, вы можете сделать это:

Это позволит вам вытащить someInt из getArguments() последним, даже если Fragment был воссоздан системой. Это более элегантное решение, чем конструктор static .

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

Update:

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

Ответ 6

Некоторый код kotlin:

И вы можете получить аргументы:

Ответ 7

Лучшая практика для фрагментов экземпляра с аргументами в android заключается в том, что в вашем фрагменте есть статический метод factory.

Вам следует избегать установки полей с экземпляром фрагмента. Потому что всякий раз, когда система Android воссоздает ваш фрагмент, если он чувствует, что системе требуется больше памяти, чем она воссоздает ваш фрагмент, используя конструктор без аргументов.

Ответ 8

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

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

Но что мы можем сделать, это проверить onCreate , что пользователь!= null, а если нет - затем вытащите его с уровня данных, в противном случае - используйте существующий.

Таким образом, мы получаем как способность воссоздать userId в случае восстановления фрагментов Android, так и привязанность к действиям пользователя, а также возможность создавать фрагменты, удерживая объект самостоятельно или только его id


Автор: ivanessence

1. Что такое Fragment?

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

Жизненный цикл фрагмента выглядит следующим образом:


– onAttach()
Вызывается, когда Fragment связывается со своей Activity, при этом элементы не инициализированы до конца. Можно использовать для получения ссылки для Activity и последующей работы с ней.
– onCreate()
Вызывается при создании фрагмента. В методе можно инициализировать компоненты, которые необходимы для работы фрагмента, но не связанные с пользовательским интерфейсом.
– onCreateView()
Фрагмент готов для инициализации пользовательского интерфейса. В данном методе необходимо указать R.layout.xxx, который содержит интерфейс фрагмента.
– onActivityCreated()
Вызывается после полной инициализации фрагмента и его родительской Activity. С текущего момента можно обращаться к объекту Context.
– onStart()
Переводит наш Fragment в состояние Started, после чего он становится виден для пользователя. Метод может использоваться для какой-либо логики, которая взаимодействует с UI.
– onResume()
Fragment становится доступен для взаимодействия с пользователем.
– onPause()
Метод вызывается когда пользователь покинул Fragment, например перешёл на другой фрагмент, либо закрыл родительскую Factivity.
– onStop()
Fragment переходит в состояние Stopped.
– onDestroyView()
Интерфейс Fragment уничтожается.
– onDestroy()
Вызывается для выполнения окончательного удаления Fragment из системы. Android не гарантирует вызов данного метода.

2. Как добавить Fragment к Activity?

Для добавления/удаления/замены Fragment в Activity необходимо воспользоваться классами FragmentManager и FragmentTransaction.

Замечу, что getFragmentManager() является deprecated методом, необходимо использовать getSupportFragmentManager() из пакета android.support.v4.app.

После создания необходимых объектов, необходимо вставить наш Fragment в xml разметку нашей Activity.

В нашей разметке находится контейнер R.id.fragment_container, который будет содержать Fragment

3. Как гарантированно добавить Fragment к Activity?

При выполнении транзакции и добавлении Fragment к Activity можно использовать асинхронный метод commit(). При передаче данных в Fragment, например отправка Broadcast или через EventBus, нет гарантии, что Fragment получит их. Гарантированную доставку данных в Fragment можно обеспечить путём использования метода commitNow() который вызывается синхронно.

4. Предназначение методов add, remove, hide, show, replace?

– add()
Добавляет Fragment в контейнер и отображает его UI, если метод onCreateView() возвращает не null.
– remove()
Удаляет существующий Fragment и его UI из контейнера, к которому он был добавлен.
– hide()
Если Fragment был добавлен к контейнеру, то метод скрывает его UI, при этом Fragment не уничтожается. Применимо только к Fragment находящемся в контейнере.
– show()
Делает Fragment видимым, который был скрыт методом hide(). Применимо только к Fragment находящемся в контейнере.
– replace()
Заменяет Fragment, которой был добавлен в контейнер, другим Fragment. Метод работает по принципу вызова remove() и затем add().

5. Как сохранить данные в Fragment при повороте экрана (изменении конфигурации)?

Fragment содержит переменную, отвечающую за сохранение экземпляра Fragment во время изменения конфигурации. По умолчанию она равна false.
Для сохранения данных, в классе Fragment необходимо установить значение в true:

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

Примеры стараюсь элементарными делать для понимания их работы, комментарии так же буду стараться приводить к каждой строчке.
Создаем проект в еклипсе. И сразу сходу смотрим есть ли в папке libs файл android-support-v4.jar, если его нету значит мы не сможем использовать фрагменты в нашей программе, по этому скачиваем его отсюда , но по идее он должен быть так как в новых сборках android sdk его вшили в проекты.

Разметка

Теперь можно начать писать приложение. Для начала мы создадим разметку что бы потом не заморачиваться по этому поводу.

layout/main.xml


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

layout-land/main.xml


Как видите тут мы вызываем уже второй фрагмент, выглядеть он будет так:


и теперь нам нужно описать второй фрагмент для склеивания в главной активности, для сглаживания

details_activity_layout.xml


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

list_mobile.xml


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

Пояснение:
У нас есть два фрагмента которые нам нужно отобразить на экране, для этого мы создали первый фрагмент которым у нас является main.xml, и создали второй details_activity_layout.xml, дальше мы создали в папочке layout-land еще один горизонтальный вид для нашего окна и в нем уже прописали как оно будет выглядеть переопределив перед этим ниши фрагменты в main и details_activity_layout.

Блин надеюсь не сложно объяснил.

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

То есть как бы по сути мы вывели при помощи фрагментов две активности в одном экране.

Фух! Ну а теперь давайте напишем код который будет делать собственно все что я описал выше.

Фрагменты

У нас сейчас есть файл MainActivity который выглядит вот так:

MainActivity


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

Дальше нам нужно создать второй FragmentActivity который будет отображать наш textView в который мы выводим текст из листвью.

DetailActivity


Тут вроде бы по комментариям понятно что и как делается, проверили какая ориентация, если вертикальная тогда проверяем что пришло с фрагмента, если не пусто то смотрим что и отображаем в текствью. Если же ориентация горизонтальная то активность финишируется и запускается фрагмент из папки layout-land.

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

ListFragment


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

Далее нам нужно создать последний фрагмент который будет выводить в горизонтальном положении наш текствью.

DetailFragment


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

Не забываем прописать FragmentActivity в манифестве, а то будут сыпаться ошибки. Всем спасибо за внимание.

Создадим простое приложение с двумя фрагментами, которое будет уметь:

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

Project name: P1051_FragmentDynamic
Build Target: Android 4.1
Application name: FragmentDynamic
Package name: ru.startandroid.develop.p1051fragmentdynamic
Create Activity: MainActivity

В strings.xml добавим строки:

Создаем фрагменты. Как мы помним из прошлого урока, для этого нам нужны будут layout-файлы и классы, наследующие android.app.Fragment

fragment1.xml:

fragment2.xml:

Fragment1.java:

Fragment2.java:

Все почти аналогично прошлому уроку, только убрали вызовы кучи lifecycle методов с логами.

Рисуем основное Activity.

Три кнопки для добавления, удаления и замены фрагментов. Чекбокс для включения использования BackStack. И FrameLayout – это контейнер, в котором будет происходить вся работа с фрагментами. Он должен быть типа ViewGroup. А элементы Fragment, которые мы использовали на прошлом уроке для размещения фрагментов, нам не нужны для динамической работы.

MainActivity.java:

В onCreate создаем пару фрагментов и находим чекбокс.

В onClick мы получаем менеджер фрагментов с помощью метода getFragmentManager. Этот объект является основным для работы с фрагментами. Далее, чтобы добавить/удалить/заменить фрагмент, нам необходимо использовать транзакции. Они аналогичны транзакциям в БД, где мы открываем транзакцию, производим операции с БД, выполняем commit. Здесь мы открываем транзакцию, производим операции с фрагментами (добавляем, удаляем, заменяем), выполняем commit.

Итак, мы получили FragmentManager и открыли транзакцию методом beginTransaction. Далее определяем, какая кнопка была нажата:

если Add, то вызываем метод add, в который передаем id контейнера (тот самый FrameLayout из main.xml) и объект фрагмента. В итоге, в контейнер будет помещен Fragment1

если Remove, то вызываем метод remove, в который передаем объект фрагмента, который хотим убрать. В итоге, фрагмент удалится с экрана.

если Replace, то вызываем метод replace, в который передаем id контейнера и объект фрагмента. В итоге, из контейнера удалится его текущий фрагмент (если он там есть) и добавится фрагмент, указанный нами.

Далее проверяем чекбокс. Если он включен, то добавляем транзакцию в BackStack. Для этого используем метод addToBackStack. На вход можно подать строку-тэг. Я передаю null.

Ну и вызываем commit, транзакция завершена.

Давайте смотреть, что получилось. Все сохраняем, запускаем приложение.



появился первый фрагмент.

Жмем Remove


Еще раз добавим первый фрагмент – жмем Add. И жмем Replace


первый фрагмент заменился вторым.

Снова запускаем приложение и включаем чекбокс add to Back Stack


Т.е. все достаточно просто и понятно. Скажу еще про пару интересных моментов.

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

Когда мы удаляем фрагмент и не добавляем транзакцию в BackStack, то фрагмент уничтожается. Если же транзакция добавляется в BackStack, то, при удалении, фрагмент не уничтожается (onDestroy не вызывается), а останавливается (onStop).

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

Читайте также: