Как передать параметры в конструктор фрагмента?
Параметры передаются в конструктор Fragment-а через Bundle, с помощью метода
Распространенная ошибка передавать данные через кастомный конструктор. Использовать не-дефолтные конструкторы фрагментов не рекомендуется, потому что фрагмент может быть уничтожен и пересоздан вследствие изменений конфигурации (например при повороте экрана).
Использование пары методов
#Fragment
Параметры передаются в конструктор Fragment-а через Bundle, с помощью метода
Fragment.setArgument(Bundle)
. Переданный бандл может быть получен через Fragment.getArguments()
в соответствующем методе жизненного цикла фрагмента.Распространенная ошибка передавать данные через кастомный конструктор. Использовать не-дефолтные конструкторы фрагментов не рекомендуется, потому что фрагмент может быть уничтожен и пересоздан вследствие изменений конфигурации (например при повороте экрана).
Использование пары методов
setArguments
/getArguments
гарантирует, что при пересоздании Bundle будет сериализован/десериализован, и данные восстановятся.#Fragment
Fragment
Fragment используется для отображения части UI на экране. Фрагмент создается внутри активити или внутри другого фрагмента.
Для создания и управления фрагментами используется FragmentManager.
Класс-наследник класса Fragment должен иметь дефолтный конструктор без параметров. Система использует этот конструктор при пересоздании фрагмента.
Начиная с API v28 системный класс Fragment – deprecated. Рекомендуется использовать Fragment из Support Library.
#Fragment
Fragment используется для отображения части UI на экране. Фрагмент создается внутри активити или внутри другого фрагмента.
Для создания и управления фрагментами используется FragmentManager.
Класс-наследник класса Fragment должен иметь дефолтный конструктор без параметров. Система использует этот конструктор при пересоздании фрагмента.
Начиная с API v28 системный класс Fragment – deprecated. Рекомендуется использовать Fragment из Support Library.
#Fragment
Расскажите про способы добавления и переключения фрагментов. Как работать с бэкстэком?
Для управления фрагментами используются два класса: FragmentManager и FragmentTransaction.
Для получения
Методы класса
add() добавляет фрагмент на активити или другой фрагмент. Принимает аргументами
Другой способ добавить фрагмент - определить в лэйауте с помощью тега
remove() - операция, обратная
replace() удаляет все фрагменты, добавленные методом
Эти операции не выполняются сразу же после вызова методов. Метод commit() завершает транзакцию и выполняет операции транзакции.
Метод addToBackStack() добавляет транзакцию в Back Stack. Это значит, что когда пользователь нажмет Back транзакция откатится.
Метод popBackStack() удаляет транзакцию с верхушки бэкстэка, возвращает
Документация.
#Fragment
Для управления фрагментами используются два класса: FragmentManager и FragmentTransaction.
Для получения
FragmentManager
используются метод активити getSupportFragmentManager()) или метод фрагмента getChildFragmentManager()).FragmentManager
начинает транзакцию и возвращает объект FragmentTransaction
вызовом метода beginTransaction().Методы класса
FragmentTransaction
, которые необходимо знать - add()
, remove()
и replace()
.add() добавляет фрагмент на активити или другой фрагмент. Принимает аргументами
containerViewId
, в который добавляется фрагмент, инстанс фрагмента, тег.Другой способ добавить фрагмент - определить в лэйауте с помощью тега
<fragment>
.remove() - операция, обратная
add()
. Удаляет фрагмент.replace() удаляет все фрагменты, добавленные методом
add()
в заданный контейнер, и добавляет переданный аргументом фрагмент в контейнер. Параметр tag
может быть null.Эти операции не выполняются сразу же после вызова методов. Метод commit() завершает транзакцию и выполняет операции транзакции.
Метод addToBackStack() добавляет транзакцию в Back Stack. Это значит, что когда пользователь нажмет Back транзакция откатится.
addToBackStack()
применяется ко всем операциям в транзакции. Например следующий код добавляет транзакцию из трех операций в бэкстэк:fragmentTransaction
.add(R.id.fragmentContainer1, fragment1)
.add(R.id.fragmentContainer2, fragment2)
.replace(R.id.fragmentContainer1, fragment3)
.addToBackStack("tag")
.commit()
Метод popBackStack() удаляет транзакцию с верхушки бэкстэка, возвращает
true
, если бэкстэк хранил хотя бы одну транзакцию.Документация.
#Fragment
Важен ли порядок, в котором добавляются операции в FragmentTransaction?
Документация описывает два случая, в которых порядок важен:
1. Метод commit() должен вызываться последним.
2. Если несколько фрагментов добавляются в один контейнер, то порядок добавления определяет порядок в котором фрагменты отрисовываются в иерархии
Есть еще третий случай. Если метод addToBackStack(String name) вызывается несколько раз на одной транзакции, то транзакция добавляется в бэкстэк один раз с тегом, который передается в последнем вызове метода.
Пример:
Создается одна транзакция с тегом
Поведение нескольких
#Fragment
Документация описывает два случая, в которых порядок важен:
1. Метод commit() должен вызываться последним.
2. Если несколько фрагментов добавляются в один контейнер, то порядок добавления определяет порядок в котором фрагменты отрисовываются в иерархии
view
.Есть еще третий случай. Если метод addToBackStack(String name) вызывается несколько раз на одной транзакции, то транзакция добавляется в бэкстэк один раз с тегом, который передается в последнем вызове метода.
Пример:
supportFragmentManager.beginTransaction()
.add(R.id.fragmentContainer, Fragment1())
.addToBackStack("add1")
.add(R.id.fragmentContainer, Fragment2())
.addToBackStack("add2")
.commit()
Создается одна транзакция с тегом
add2
, которая добавляет сразу два фрагмента. При нажатии кнопки Back оба фрагмента будут удалены.Поведение нескольких
addToBackStack()
не задокументировано и может различаться на разных версиях ОС, так что не забудьте на собеседовании сказать, что вы бы так никогда делать не стали.#Fragment
Чем отличается tag в методах add() и addToBackStack()?
Тег фрагмента используется в методе findFragmentByTag().
Tag в методе addToBackStack() это на самом деле не
Этот вопрос возник на собеседованиях, потому что когда только появились фрагменты было популярно писать такой код:
Сначала добавляется фрагмент с одинаковым тегом фрагмента и именем транзакции. Потом, используя имя-тег, можно получить инстанс фрагмента по позиции в бэкстэке.
Удобно? Нет! Не надо так делать.
#Fragment
Tag
в методе add() присваивается фрагменту. Fragment.getTag() возвращает этот тег.Тег фрагмента используется в методе findFragmentByTag().
Tag в методе addToBackStack() это на самом деле не
tag
, а name
. Имя транзакции, которое присваивается объекту BackStackEntry и возвращается методом getName().Этот вопрос возник на собеседованиях, потому что когда только появились фрагменты было популярно писать такой код:
val tag = "home_fragment"
supportFragmentManager.beginTransaction()
.add(R.id.fragmentContainer, HomeFragment, tag)
.addToBackStack(tag)
.commit();
…
val lastEntryIndex = supportFragmentManager.backStackEntryCount - 1
val tag = supportFragmentManager.getBackStackEntryAt(lastEntryIndex).name
val topFragment = supportFragmentManager.findFragmentByTag(tag)
Сначала добавляется фрагмент с одинаковым тегом фрагмента и именем транзакции. Потом, используя имя-тег, можно получить инстанс фрагмента по позиции в бэкстэке.
Удобно? Нет! Не надо так делать.
#Fragment
Метод FragmentManager.commit() – синхронный или нет?
– Асинхронный.
Это значит, что транзакция не выполняется во время вызова метода. commit() добавляет транзакцию в очередь главного потока и транзакция выполняется при первой возможности.
Чтобы выполнить транзакцию синхронно, можно воспользоваться методом commitNow() вместо
#Fragment
– Асинхронный.
Это значит, что транзакция не выполняется во время вызова метода. commit() добавляет транзакцию в очередь главного потока и транзакция выполняется при первой возможности.
Чтобы выполнить транзакцию синхронно, можно воспользоваться методом commitNow() вместо
commit()
или вызвать executePendingTransactions() после метода commit()
.#Fragment