JetPack Navigation: как получить текущий Fragment
Компонент Navigation помогает разработчикам разгрести непонятный мусор, связанный с кучей вызовов разных экранов из разных мест. Уже достаточно давно я написал небольшой хендлер Router для открытия Activity и проброски каких-то параметров внутри. Выглядело это, например, вот так
Любой вызов Activity дергал один и тот же метод внутри самой Activity. И это было достаточно удобно — вместо судорожного поиска по проекту, где же я вызвал startActivity(intent), я просто открывал нужную мне Activity и открывал все использования метода open.
С фрагментами все было не так просто. Да, я работал по схожей схеме
Но у меня не было общего класса типа FragmentRouter, и открывал я их с помощью fragmentTransaction, что было порой не очень удобно (что связано было например с Fragment.hide() и обработкой показа действительно текущего фрагмента, а не где-то спрятанного). Поэтому к компоненту JetPack Navigation я присматривался с очень большим интересом.
Раскрою свою мысль про обработку фрагментов чуть дальше.
Мне необходимо отслеживать изменения на открытый Fragment (впрочем, как и на закрытый), причем неважно кто является Fragment Host — Activity или какой-то другой фрагмент. Для этого какое-то время назад я написал небольшой классик FragmentConnector, который
а). Отправлял изменения о текущем фрагменте в вышестоящий хост (onResume / onPause)
б). Сохранял текущий фрагмент в хосте, чтобы его можно было отслеживать в любой удобный момент.
Таким образом иерархия Activity — Fragment у меня была довольно простая — Activity со стеком фрагментов, каждый из которых мог хранить в свою очередь свой стек фрагментов… и так далее.
Компонент Navigation немного сломал эту структуру. Там есть условная Activity, в ней есть NavHostFragment (который, если я не ошибаюсь, сам является фрагментом), в нем уже хранятся конкретно отображаемые фрагменты, в которых может быть свой NavHostFragment… и так далее
Итак, далее я покажу измененные классы с примерами использования и объяснения как это работает
FragmentConnector
Суть крайне проста — соответственные методы вызываются в нужных местах базового фрагмента (главный предок всех ваших фрагментов)
Использование FragmentConnector в базовом фрагменте
Тут тоже все просто — в методах onResume, onPause и onHiddenChanged дергаем метод fragmentConnector. Ключевое отличие от не-Navigation находится в строчке
?: (parentFragment as? NavHostFragment)?.parentFragment as? FragmentConnector
Просто углубляемся на уровень ниже вместе с NavHostFragment, как я говорил выше.
Использование FragmentConnector в базовой Activity
Получение изменений о текущем фрагменте в Activity / Fragment
Бонус: получение ParentFragment
Если у нас фрагмент вызывается внутри другого фрагмента, то получить его через parentFragment c Navigation Component не получится. Используем такой способ