Работа с фрагментами в kotlin

Небольшой гайд по работе с фрагментами в android studio.

Фрагменты чем то напоминают фреймы в html. Фрагменты обладают многими возможностями, которые есть у активити (Activity), имеют свой lifecycle, также работают с viewModel и т.п. И конечно же фрагмент имеет собственный шаблон (layout).

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

Пусть у нас в шаблоне активити есть вот такой элемент:

Позиционирование и размеры, которые я опустил, будут определятся уже контейнером шаблона активити, нам для определенности нужен только id компонента.

Создание фрагмента

Также мы создали фрагмент (New -> Fragment -> FragmentBlank), который назвали ItemFragment. IDE создаст два файла — в одном из них будет наследник класса Fragment, а в другом — шаблон фрагмента.

Чем хорошо создание фрагмента через IDE, это тем, что мы получаем заготовку с использованием всех новых best — практик, которые приняты на данный момент.

Рассмотрим этот шаблон:

Как видно из примера выше — IDE создает заготовку фрагмента с двумя входными параметрами. Параметры передаются через аргументы фрагмента в onCreate (а не аргументы конструктора класса), а для создания фрагмента, предлагается использовать «фабричный» подход — статический метод newInstance.

В onCreateView мы подключаем шаблон.

Еще одно важное событие — onViewCreated — для которого не создаётся перегрузки по умолчанию, но которое обычно переопределяется разработчиком.

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

Параметры фрагмента

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

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

В шаблоне от IDE продемонстрирован правильный подход к работе с параметрами.

Подключение фрагмента

Теперь нам нужно подключить фрагмент в соответствующий компонент активити (в нашем примере у него id = item_container).

Обычно это делают в onCreate вот так:

Во первых видно, что используется supportFragmentManager, который требует начать транзакцию beginTransaction(), а в конце выполнить её commit(). Об этом механизме можно не думать, т.к. нам важна операция добавления.

Мы указываем компонент контейнера по его ID и передаём фрагмент, воспользовавшись фабричным методом из шаблона, созданного IDE.

Но для чего делается проверка (?!) :

При пересоздании активити, андроид сам выполняет пересоздание фрагмента. Потому от нас требуется создать фрагмент только, если это первый запуск создания активити. Иначе, например, при повороте экрана, фрагмент будет создаваться дважды — в onCreate активити и платформой android.

Также лучше не использовать метод add, а заменить его на метод replace.

FragmentContainerView отобразит все контейнеры, добавленные в него (add). Так можно реализовать многослойный вывод, к примеру. При этом, каждый слой сможет иметь свою viewModel и шаблон и т.д.

Но обычно требуется подключить какой то конкретный фрагмент, а остальные (если они там были) удалить — используйте replace.

Навигация с фрагментами

Если важна история добавления фрагментов, т.е. есть какая то логика в этом для приложения, то можно добавлять фрагменты в стек навигации (т.н. BackStack).

Андроид при этом запоминает состояния в связке активити + фрагменты и позволяет вернуться к предыдущему состоянию при нажатии кнопки «назад».

Добавление фрагмента будет выглядеть вот так:

Чтобы выбросить с вершины стека имеющийся там фрагмент, можно вызвать

addToBackStack позволяет именовать навигационные элементы (в примере передан null вместо имени), тогда при необходимости можно вернуться к состоянию бек-стека по его имени.

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

Завершение работы с фрагментом, обратная связь с активити

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

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

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

Рекомендованный путь похож на первый вариант, но с некоторыми деталями. Мы должны объявить в нашем фрагменте интерфейс вроде следующего:

Теперь, если мы хотим использовать фрагмент, родитель (активити) должен реализовать этот интерфейс.

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

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

А когда приходит момент вызова кол-бека, то выполняется код:

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

Написать комментарий

Мало букафф? Читайте есчо !

View Binding в kotlin

Февраль 15, 2025 г.

Иногда на собесах спрашивают что такое view binding, и звучит это как некая сложная тема, но на самом деле, это просто фича сборщика, которую можно использовать для упрощения доступа к элементам шаблонов. Этот механизм упрощает работу с элементами ...

Читать

Cannot find implementation for Database. Database_Impl does not exist (Room)

Февраль 11, 2025 г.

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

Читать

 

Комментарии к «Работа с фрагментами в kotlin»

Понравилась статья? Есть вопросы? - пишите в комментариях.



Комментарий: