Добавление UI-фрагмента во FragmentManager
Когда в Honeycomb появился класс
Fragment
, в класс
Activity
были внесены изменения: в него был добавлен
компонент,
называемый
FragmentManager
.
FragmentManager
работает с двумя вещами: списком
фрагментов и обратным стеком транзакций (о котором вы
скоро узнаете) (рис. 8.13). Он отвечает за добавление
представлений фрагментов в иерархию представлений activity
и управление жизненными циклами фрагментов.
В приложении CriminalIntent нас интересует только список
фрагментов
Fragment
Manager
.
Рис. 8.13. Компонент FragmentManager
Транзакции фрагментов
После получения объекта
FragmentManager
добавьте
следующий код, который передает ему фрагмент для
управления. (Позднее мы рассмотрим этот код более подробно,
а пока просто включите его в приложение.)
Листинг 8.12. Добавление CrimeFragment (MainActivity.kt)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState:
Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val currentFragment =
supportFragmentManager.findFragment
ById(R.id.fragment_container)
if (currentFragment == null) {
val fragment = CrimeFragment()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container,
fragment)
.commit()
}
}
}
Для добавления фрагмента в код activity выполняются явные
вызовы во
Fragment
Manager
activity. Доступ к менеджеру
фрагментов
осуществляется
с
помощью
свойства
supportFragmentManager
.
Мы
будем
использовать
supportFragmentManager
, так как используем Jetpack-
библиотеку и класс
AppCompatActivity
. У имени есть
префикс support, так как свойство возникло в библиотеке
поддержки v4, но с тех пор библиотека поддержки была
перенесена в Jetpack как библиотека
androidx
.
Разбираться в остальном коде, добавленном в листинг 8.12,
лучше всего не с начала. Найдите операцию
add(...)
и
окружающий ее код. Этот код создает и закрепляет транзакцию
фрагмента.
if (currentFragment == null) {
val fragment = CrimeFragment()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container,
fragment)
.commit()
}
Транзакции фрагментов используются для добавления,
удаления, присоединения, отсоединения и замены фрагментов
в списке фрагментов.
Они позволяют объединять операции в группы, например
добавлять несколько фрагментов в разные контейнеры. Они
лежат в основе механизма использования фрагментов для
формирования и модификации экранов во время выполнения.
FragmentManager
ведет стек транзакций, по которому вы
можете перемещаться. Если в транзакции присутствует
несколько операций, то при удалении транзакции из обратного
стека их порядок реверсируется. Это позволяет лучше
контролировать состояние пользовательского интерфейса при
группировании операций с фрагментами в одну транзакцию.
Функция
FragmentManager.beginTransaction()
создает
и возвращает экземпляр
FragmentTransaction
. Класс
FragmentTransaction
использует динамичныйинтерфейс:
функции, настраивающие
FragmentTransaction
, возвращают
FragmentTransaction
вместо
Unit
,
что
позволяет
объединять их вызовы в цепочку. Таким образом, выделенный
код в приведенном выше листинге означает: «Создать новую
транзакцию фрагмента, включить в нее одну операцию add, а
затем закрепить».
Функция
add(...)
отвечает за основное содержание
транзакции. Она получает два параметра: идентификатор
контейнерного представления и недавно созданный объект
CrimeFragment
.
Идентификатор
контейнерного
представления должен быть вам знаком: это идентификатор
ресурса элемента
FrameLayout
, определенного в файле
activity_crime.xml
.
Идентификатор контейнерного представления выполняет
две функции:
• сообщает
FragmentManager
, где в представлении activity
должно находиться представление фрагмента;
• обеспечивает однозначную идентификацию фрагмента в
списке
Fragment
Manager
.
Когда вам потребуется получить экземпляр
CrimeFragment
от
FragmentManager
, запросите его по идентификатору
контейнерного представления.
val currentFragment =
supportFragmentManager.findFragmentById
(R.id.fragment_container)
if (currentFragment == null) {
val fragment = CrimeFragment()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit()
}
Может показаться странным, что
FragmentManager
идентифицирует
CrimeFragment
по идентификатору ресурса
FrameLayout
. Однако идентификация UI-фрагмента по
идентификатору ресурса его контейнерного представления
встроена в механизм работы
FragmentManager
. Если вы
добавляете в activity несколько фрагментов, то обычно для
каждого фрагмента создается отдельный контейнер со своим
идентификатором.
Теперь мы можем кратко описать код, добавленный в
листинг 8.12, от начала до конца.
Сначала у
FragmentManager
запрашивается фрагмент с
идентификатором
контейнерного
представления
R.id.fragmentContainer
. Если этот фрагмент уже находится
в списке,
FragmentManager
возвращает его.
Почему фрагмент может уже находиться в списке? Вызов
MainActivity.onCreate (Bundle?)
может быть выполнен в
ответ на воссоздание объекта
MainActivity
после его
уничтожения из-за поворота устройства или освобождения
памяти.
При
уничтожении
activity
ее
экземпляр
FragmentManager
сохраняет список фрагментов. При
воссоздании activity новый экземпляр
FragmentManager
загружает список и воссоздает хранящиеся в нем фрагменты,
чтобы все работало как прежде.
С другой стороны, если фрагменты с заданным
идентификатором контейнерного представления отсутствуют,
значение
fragment
равно
null
. В этом случае мы создаем
новый экземпляр
CrimeFragment
и новую транзакцию,
которая добавляет фрагмент в список.
Теперь
MainActivity
— это хост для
CrimeFragment
.
Чтобы убедиться в этом, запустите приложение CriminalIntent.
На экране отображается представление, определенное в файле
fragment_crime.xml
(рис. 8.14).
Do'stlaringiz bilan baham: |