- Управление фрагментами
- Взаимодействие с фрагментами
- Пример фрагментов — Телефон
- 1. Создание проекта Android
- 2. Добавление данных
- 3. Создание PlayQuoteFragment
- 4. Создание PlayQuoteActivity
- 5. Создание TitlesFragment
- Отображение TitlesFragment в MainActivity
- Запуск приложения
- Managing Fragments
- Communicating with Fragments
- Создание фрагмента
- Добавление фрагмента в действие
- Декларативное использование фрагмента
- Регистр имени пакета
- Жизненный цикл фрагмента
- Методы жизненного цикла при создании фрагмента
- Методы жизненного цикла при уничтожении фрагмента
- Использование SetRetainInstance
- Управление состоянием фрагмента
- Ограничения при использовании Bundle
- Участие в работе меню
Управление фрагментами
Для упрощения управления фрагментами Android предоставляет FragmentManager класс. У каждого действия есть экземпляр Android.App.FragmentManager , который будет находить или динамически изменять его фрагменты. Каждый набор этих изменений называется транзакциейи выполняется с помощью одного из интерфейсов API, содержащихся в классе , управляемом FragmentManager . Действие может запустить транзакцию следующего вида:
Эти изменения в фрагментах выполняются в FragmentTransaction экземпляре с помощью таких методов, как Add() , Remove(), а Replace(). изменения затем применяются с помощью Commit() . Изменения в транзакции не выполняются немедленно. Вместо этого они планируются для выполнения в потоке пользовательского интерфейса действия как можно скорее.
В следующем примере показано, как добавить фрагмент в существующий контейнер:
Если транзакция фиксируется после Activity.OnSaveInstanceState() вызова метода, создается исключение. Это происходит потому, что когда действие сохраняет свое состояние, Android также сохраняет состояние всех размещенных фрагментов. Если после этой точки фиксируются какие-либо транзакции фрагментов, состояние этих транзакций будет потеряно при восстановлении действия.
Можно сохранить транзакции фрагмента в стеке действия, вызвав метод . Это позволяет пользователю перемещаться назад через изменения фрагмента при нажатии кнопки назад . Без вызова этого метода фрагменты, которые удаляются, будут уничтожены и будут недоступны, если пользователь вернется назад по действию.
В следующем примере показано, как использовать AddToBackStack метод объекта FragmentTransaction для замены одного фрагмента, сохраняя состояние первого фрагмента в стеке назад:
Взаимодействие с фрагментами
Фрагментманажер знает обо всех фрагментах, присоединенных к действию, и предоставляет два метода, помогающие найти эти фрагменты:
Финдфрагментбид — этот метод найдет фрагмент, используя идентификатор, указанный в файле макета, или идентификатор контейнера, когда фрагмент был добавлен как часть транзакции.
Финдфрагментбитаг — этот метод используется для поиска фрагмента, имеющего тег, который был предоставлен в файле макета или был добавлен в транзакцию.
Как фрагменты, так и действия ссылаются на FragmentManager , поэтому одни и те же методы используются для обмена данными между ними. Приложение может найти фрагмент ссылки с помощью одного из этих двух методов, привести ссылку на соответствующий тип, а затем напрямую вызвать методы в фрагменте. В следующем фрагменте кода приведен пример.
Кроме того, действие может использовать FragmentManager для поиска фрагментов:
Источник
Пример фрагментов — Телефон
Это первая часть пошагового руководства, в рамках которого будет создано приложение Xamarin.Android, предназначенное для устройства Android в книжной ориентации. В этом пошаговом руководстве рассказывается, как создавать фрагменты в Xamarin.Android и как добавлять их в пример.
Для этого приложения будут созданы следующие классы:
- PlayQuoteFragment — этот фрагмент позволяет отобразить цитату из пьесы Уильяма Шекспира. Он размещается в PlayQuoteActivity .
- Shakespeare — этот класс будет содержать два жестко зафиксированных массива в качестве свойств.
- TitlesFragment — этот фрагмент позволяет отобразить список названий пьес, написанных Уильямом Шекспиром. Он размещается в MainActivity .
- PlayQuoteActivity TitlesFragment Запустится PlayQuoteActivity в ответ на пользователя, который выбирает воспроизведение в TitlesFragment .
1. Создание проекта Android
Создайте проект Xamarin.Android с именем FragmentSample.
Для работы с этим пошаговым руководством рекомендуем выбрать современную разработку.
После создания проекта переименуйте файл layout/Main.axml в layout/activity_main.axml.
2. Добавление данных
Данные для этого приложения будут храниться в двух жестко зафиксированных строковых массивах, являющихся свойствами имени класса Shakespeare :
- Shakespeare.Titles — этот массив будет содержать список пьес Уильяма Шекспира. Это источник данных для TitlesFragment .
- Shakespeare.Dialogue — этот массив будет содержать список цитат из одной из пьес, указанных в Shakespeare.Titles . Это источник данных для PlayQuoteFragment .
Добавьте новый класс C# в проект FragmentSample и присвойте ему имя Shakespeare.cs. В этом файле создайте новый класс C# с именем Shakespeare и следующим содержимым:
3. Создание PlayQuoteFragment
С помощью фрагмента Android PlayQuoteFragment будет отображаться цитата из пьесы Шекспира, выбранной пользователем ранее в приложении. Этот фрагмент не будет использовать файл макета Android, а будет динамически создавать свой пользовательский интерфейс. Добавьте в проект новый класс Fragment с именем PlayQuoteFragment .
Затем измените код этого фрагмента таким образом, чтобы он соответствовал следующему фрагменту кода:
В приложениях Android часто используется методика предоставления фабричного метода, с помощью которого будет создаваться экземпляр фрагмента. Это гарантирует, что фрагмент будет создан с необходимыми параметрами для правильной работы. В этом пошаговом руководстве предполагается, что приложение применит метод PlayQuoteFragment.NewInstance для создания нового фрагмента при каждом выборе цитаты. NewInstance Метод принимает один параметр — индекс цитаты для вывода.
Android будет вызывать метод OnCreateView для отображения фрагмента на экране. Метод возвращает объект Android View , который является фрагментом. Этот фрагмент не использует файл макета для создания представления. Вместо этого он будет программными средствами создавать представление, создавая экземпляр TextView для хранения цитаты, и отображать мини-приложение в ScrollView.
Подклассы фрагмента должны использовать открытый конструктор по умолчанию без параметров.
4. Создание PlayQuoteActivity
Фрагменты должны размещаться внутри действия. Поэтому для этого приложения нужно создать действие, в котором будет размещаться PlayQuoteFragment . Действие позволит динамически добавить этот фрагмент в макет во время выполнения. Добавьте в приложение новое действие и присвойте ему имя PlayQuoteActivity .
Измените код в PlayQuoteActivity следующим образом:
При создании PlayQuoteActivity он будет создавать экземпляр нового фрагмента PlayQuoteFragment и загружать его в корневое представление в контексте FragmentTransaction . Обратите внимание, что при этом действии файл макета Android не загружается для пользовательского интерфейса. Вместо этого в корневое представление приложения добавляется новый фрагмент PlayQuoteFragment . Идентификатор ресурса Android.Resource.Id.Content используется для ссылки на корневое представление действия без указания его идентификатора.
5. Создание TitlesFragment
TitlesFragment позволяет создать подкласс специализированного фрагмента, известного как ListFragment , который содержит логику для отображения ListView в нашем фрагменте. ListFragment предоставляет свойство ListAdapter (которое ListView использует для отображения содержимого) и обработчик событий с именем OnListItemClick , что позволяет фрагменту реагировать на нажатия строки, отображаемой ListView .
Чтобы приступить к работе, добавьте в проект новый фрагмент и присвойте ему имя TitlesFragment:
Измените код внутри фрагмента следующим образом:
При создании действия Android вызовет метод OnCreate из фрагмента. На этом этапе создается адаптер списка для ListView . Метод ShowQuoteFromPlay запустит экземпляр PlayQuoteActivity , чтобы отобразить цитату из выбранной пьесы.
Отображение TitlesFragment в MainActivity
И наконец, нам нужно отобразить TitlesFragment внутри MainActivity . При действии фрагмент не загружается динамически. Вместо этого фрагмент будет статически загружен путем объявления его в элементе fragment файла макета для этого действия. Загружаемый фрагмент определяется путем назначения атрибута android:name классу фрагмента (включая пространство имен для типа). Например, для использования TitlesFragment свойству android:name нужно присвоить значение FragmentSample.TitlesFragment .
Измените файл макета activity_main.axml, заменив существующий XML следующим:
Атрибут class — допустимая замена для android:name . Нет официальных рекомендаций по выбору того или иного варианта. Во многих базах кода class и android:name применяются наравне друг с другом.
В действие MainActivity не нужно вносить никаких изменений кода. Код в этом классе теперь быть выглядеть примерно так:
Запуск приложения
Теперь, когда весь код готов, запустите приложение на устройстве, чтобы увидеть его в работе.
В рамках части 2 этого пошагового руководства вы оптимизируете это приложение для устройств, работающих в альбомном режиме.
Источник
Managing Fragments
To help with managing Fragments, Android provides the FragmentManager class. Each Activity has an instance of Android.App.FragmentManager that will find or dynamically change its Fragments. Each set of these changes is known as a transaction, and is performed by using one of the APIs contained in the class Android.App.FragmentTransation , which is managed by the FragmentManager . An Activity may start a transaction like this:
These changes to the Fragments are performed in the FragmentTransaction instance by using methods such as Add() , Remove(), and Replace(). The changes are then applied by using Commit() . The changes in a transaction are not performed immediately. Instead, they are scheduled to run on the Activity’s UI thread as soon as possible.
The following example shows how to add a Fragment to an existing container:
If a transaction is committed after Activity.OnSaveInstanceState() is called, an exception will be thrown. This happens because when the Activity saves its state, Android also saves the state of any hosted Fragments. If any Fragment transactions are committed after this point, the state of these transactions will be lost when the Activity is restored.
It’s possible to save the Fragment transactions to the Activity’s back stack by making a call to FragmentTransaction.AddToBackStack() . This allows the user to navigate backwards through Fragment changes when the Back button is pressed. Without a call to this method, Fragments that are removed will be destroyed and will be unavailable if the user navigates back through the Activity.
The following example shows how to use the AddToBackStack method of a FragmentTransaction to replace one Fragment, while preserving the state of the first Fragment on the back stack:
Communicating with Fragments
The FragmentManager knows about all of the Fragments that are attached to an Activity and provides two methods to help find these Fragments:
FindFragmentById – This method will find a Fragment by using the ID that was specified in the layout file or the container ID when the Fragment was added as part of a transaction.
FindFragmentByTag – This method is used to find a Fragment that has a tag that was provided in the layout file or that was added in a transaction.
Both Fragments and Activities reference the FragmentManager , so the same techniques are used to communicate back and forth between them. An application may find a reference Fragment by using one of these two methods, cast that reference to the appropriate type, and then directly call methods on the Fragment. The following snippet provides an example:
It is also possible for the Activity to use the FragmentManager to find Fragments:
Источник
Создание фрагмента
Чтобы создать фрагмент, класс должен унаследовать от Android.App.Fragment , а затем переопределить метод OnCreateView . OnCreateView вызывается действием, в котором размещен фрагмент, когда приходит время отображать этот фрагмент на экране, и возвращает View . Типичный метод OnCreateView создает View , расширяя файл макета и присоединяя его к родительскому контейнеру. Характеристики контейнера важны, так как Android будет применять параметры макета родительского элемента к пользовательскому интерфейсу фрагмента. Проиллюстрируем это на примере.
Приведенный выше код расширит представление Resource.Layout.Example_Fragment и добавит его в качестве дочернего представления в контейнер ViewGroup .
Подклассы фрагмента должны иметь открытый конструктор без аргументов по умолчанию.
Добавление фрагмента в действие
Существует два способа разместить фрагмент внутри действия:
Декларативно — фрагменты можно использовать декларативно в файлах макета с помощью тега.
Программно — фрагменты также можно создавать динамически с помощью API класса.
Программное использование через класс FragmentManager будет обсуждаться в этом руководстве позднее.
Декларативное использование фрагмента
Чтобы добавить фрагмент через макет, следует использовать тег и указать нужный фрагмент по его атрибуту class или android:name . Следующий фрагмент кода демонстрирует, как с помощью атрибута class объявить fragment .
В следующем фрагменте кода показано, как объявить fragment с помощью атрибута android:name , который идентифицирует класс Fragment.
Во время создания действия Android создает экземпляр каждого фрагмента, указанного в файле макета, и добавляет вместо элемента Fragment представление, которое создается из OnCreateView . Фрагменты, добавленные в действие декларативно, являются статическими и сохраняются в действии до его уничтожения. Вы не сможете динамически заменить или удалить фрагмент в период существования действия, к которому он прикреплен.
Каждому фрагменту должен быть назначен уникальный идентификатор:
Android: ID — как и другие элементы пользовательского интерфейса в файле макета, это уникальный идентификатор.
Android: Tag — этот атрибут является уникальной строкой.
Если не используется ни один из указанных выше методов, фрагмент принимает идентификатор представления контейнера. В следующем примере не назначен ни идентификатор android:id , ни идентификатор android:tag , поэтому Android назначает фрагменту идентификатор fragment_container .
Регистр имени пакета
Android не позволяет использовать прописные буквы в именах пакетов. Если имя пакета содержит прописную букву, при попытке расширить представление создается исключение. Впрочем, Xamarin.Android менее требователен и допускает прописные буквы в пространстве имен.
Например, оба следующих фрагмента кода будут нормально работать в Xamarin.Android, но второй из них приводит к исключению android.view.InflateException в приложении Java на чистом Android.
Жизненный цикл фрагмента
У фрагментов есть собственный жизненный цикл, который хоть и зависит от жизненного цикла действия, в котором он размещен, но имеет некоторую степень свободы. Например, приостановка действия приводит к приостановке всех связанных с ним фрагментов. Жизненный цикл фрагмента представлен на схеме ниже.
Методы жизненного цикла при создании фрагмента
Следующий список демонстрирует поток обратных вызовов в жизненном цикле фрагмента, которые выполняются при его создании.
OnInflate() — Вызывается при создании фрагмента в виде части макета представления. Он может вызываться немедленно после декларативного создания фрагмента из XML-файла макета. Фрагмент еще не связан с действием, но ему из иерархии представлений передаются в качестве параметров значения Activity, Bundle и AttributeSet. Этот метод лучше всего использовать для анализа AttributeSet и сохранения любых атрибутов, которые могут впоследствии потребоваться фрагменту.
OnAttach() — Вызывается после того, как фрагмент связан с действием. Это первый метод, который вызывается после готовности фрагмента к использованию. Обычно фрагмент не должен реализовывать конструктор или переопределять конструктор по умолчанию. Любые компоненты, которые нужны для работы фрагмента, следует инициализировать в этом методе.
OnCreate() — Вызывается действием для создания фрагмента. В момент вызова этого метода иерархия представлений того действия, в котором размещается фрагмент, может быть готова еще не полностью, поэтому фрагмент не может полагаться на любые сегменты этой иерархии раньше следующих этапов жизненного цикла фрагмента. Например, не используйте этот метод для оптимизации или настройки пользовательского интерфейса приложения. Это самый ранний момент, когда фрагмент может начать сбор нужной информации. Фрагмент на этом этапе выполняется в потоке пользовательского интерфейса, поэтому не выполняйте здесь никаких длительных вычислений, а при необходимости выносите их в фоновый поток. Этот метод может быть пропущен, если вызывается SetRetainInstance(true) . Этот вариант будет рассмотрен подробнее ниже.
OnCreateView() — Создает представление для фрагмента. Этот метод вызывается в тот момент, когда завершается метод OnCreate() соответствующего действия. В этот момент уже можно безопасно взаимодействовать с иерархией представлений действия. Этот метод должен возвращать представление, которое будет использоваться этим фрагментом.
OnActivityCreated() — Вызывается действием размещения после завершения OnActivityCreated() . На этом этапе следует выполнять окончательную оптимизацию пользовательского интерфейса.
OnStart() — Вызывается после возобновления содержащего его действия. С этого момента фрагмент становится виден пользователю. Во многих случаях фрагменты содержат код, который мог бы находиться методе OnStart() соответствующего действия.
OnResume() — Это последний метод, вызываемый перед тем, как пользователь сможет взаимодействовать с фрагментом. В качестве примера кода, который можно выполнять в этом методе, можно предложить включение функций устройства, с которым может взаимодействовать пользователь, например камеры или системы позиционирования. Службы такого рода иногда требуют значительной энергии, поэтому приложению следует минимизировать их использование для продления времени работы от батареи.
Методы жизненного цикла при уничтожении фрагмента
В следующем списке описаны методы жизненного цикла, которые вызываются по мере уничтожения фрагмента.
OnPause() — Пользователь больше не может взаимодействовать с фрагментом. Эта ситуация возникает, если операция в другом фрагменте изменяет этот фрагмент или если действие, в котором размещается фрагмент, приостановлено. Вполне возможно, что действие с этим фрагментом еще отображается на экране, то есть оно может быть полупрозрачным или занимать не весь экран. Активация этого метода является первым признаком того, что пользователь покидает этот фрагмент. Здесь фрагменту следует сохранить все нужные изменения.
OnStop() — Фрагмент больше не отображается. Возможно, остановилась работа соответствующего действия или операция фрагмента изменяет его состояние в действии. Этот обратный вызов имеет такое же назначение, как и Activity.OnStop.
OnDestroyView() — Этот метод вызывается для очистки ресурсов, связанных с представлением. Он вызывается при уничтожении представления, с которым связан этот фрагмент.
OnDestroy() — Этот метод вызывается, когда фрагмент больше не используется. Он все еще связан с действием, но уже не функционирует. В этом методе следует очистить все ресурсы, которые использует фрагмент, например используемый камерой ресурс SurfaceView. Этот метод может быть пропущен, если вызывается SetRetainInstance(true) . Этот вариант будет рассмотрен подробнее ниже.
OnDetach() — Этот метод вызывается непосредственно перед тем, как фрагмент больше не связан с действием. В этот момент иерархия фрагмента уже не существует, и сейчас самое время освободить все ресурсы, которые использует фрагмент.
Использование SetRetainInstance
Фрагмент может указать, что его не нужно уничтожать полностью, если действие будет создано повторно. Для этой цели класс Fragment предоставляет метод SetRetainInstance . Если этому методу передать аргумент true , при восстановлении действия в нем будет размещен тот же экземпляр этого фрагмента. В таком случае будут вызваны все методы обратного вызова из жизненного цикла фрагмента, кроме OnCreate и OnDestroy . Этот процесс иллюстрируется на схеме жизненного цикла выше (обозначен зеленым пунктиром).
Управление состоянием фрагмента
Фрагменты могут сохранять и восстанавливать свое состояние в течение своего жизненного цикла, используя экземпляр Bundle . Bundle позволяет фрагменту сохранять данные как пары «ключ — значение», что удобно для хранения несложных, для которых не требуется много памяти. Фрагмент может сохранить состояние, вызвав OnSaveInstanceState .
При создании нового экземпляра фрагмента состояние, сохраненное в Bundle , становится доступным новому экземпляру через методы OnCreate , OnCreateView и OnActivityCreated нового экземпляра. В следующем примере демонстрируется извлечение значения current_choice из Bundle .
Переопределение OnSaveInstanceState считается правильным приемом для сохранения временных данных фрагмента при изменениях ориентации, таких как значение current_choice из примера выше. Однако стандартная реализация OnSaveInstanceState самостоятельно управляет сохранением временных данных пользовательского интерфейса для каждого представления, которому присвоен идентификатор. Вот пример приложения, в котором XML определяет элемент EditText :
Поскольку элементу управления EditText назначен идентификатор id , этот фрагмент автоматически сохраняет данные в мини-приложении при вызове OnSaveInstanceState .
Ограничения при использовании Bundle
Несмотря на простоту сохранения временных данных с помощью OnSaveInstanceState , этот метод имеет ряд ограничений.
Если фрагмент не добавляется в стек назад, то его состояние не будет восстановлено при нажатии пользователем кнопки назад .
Если для сохранения данных используется Bundle, эти данные сериализуются. Это может приводить к задержкам в обработке.
Участие в работе меню
Фрагменты могут добавлять пункты в меню действия, в котором они размещаются. Действие всегда вначале обрабатывает пункты меню. Если у действия нет соответствующего обработчика, событие передается фрагменту, который его затем обработает.
Чтобы добавить пункты в меню действия, фрагмент должен выполнить два условия. Во-первых, фрагмент должен реализовать метод OnCreateOptionsMenu и разместить пункты в меню, как показано в примере кода ниже.
Меню в предыдущем фрагменте кода расширяется из представленного ниже кода XML, который хранится в файле menu_fragment_vehicle_list.xml .
Затем фрагмент должен вызывать SetHasOptionsMenu(true) . Вызов этого метода сообщает платформе Android, что фрагмент намерен добавить пункты меню в существующее меню параметров. Если не вызвать этот метод, пункты меню из фрагмента не добавляются в меню параметров соответствующего действия. Обычно этот процесс выполняется в методе жизненного цикла OnCreate() , как показано в фрагменте кода ниже.
На следующем снимке экрана представлено, как будет выглядеть созданное меню.
Источник