- Android Fragment Result Listener
- Как это работает?
- Как это выглядит в коде?
- Передача данных
- Получение данных
- Parent Fragment Manger
- Тестирование
- Передача данных
- Получение данных
- Вывод
- Урок 15. Передача данных между экранами — пунктами назначения. Android Navigation. Bundle vs Safe Args
- На этом уроке
- Передача данных между экранами
- Bundle или Safe Args?
- Создаем проект
- Создаем граф навигации
- Добавляем пункты назначения – фрагменты
- Как в Android’е передать переменную из фрагмента в активность?
Android Fragment Result Listener
В Android передача данных между фрагментами может осуществляться разными способами: передача через родительскую Activity, используя ViewModel или даже Fragments API. Fragment Target API с недавних пор получил статус Deprecated и вместо него Google рекомендует использовать Fragment result API.
Что такое Fragment result API? Это новый инструмент от Google который позволяет передавать данные между фрагментами по ключу. Для этого используется FragmentManager, который в свою очередь реализует интерфейс FragmentResultOwner. FragmentResultOwner выступает в качестве центрального хранилища для данных, которые мы передаем между фрагментами.
Как это работает?
Как упоминалось выше, наш FragmentManager реализует интерфейс FragmentResultOwner, который хранит в себе ConcurrentHashMap . Эта HashMap хранит наши Bundle-ы по строковому ключу. Как только один из фрагментов подписывается (или уже подписан) то он получает результат по тому самому ключу.
Что важно знать:
- Если какой-либо фрагмент подписывается на результат методом setResultFragmentListener() после того, как отправляющий фрагмент вызовет setFragmentResult() , то он немедленно получит результат
- Каждую связку “Key + Result (Bundle)“ фрагмент получает только 1 раз
- Фрагменты которые находятся в бек стеке получат результат только после того как перейдут в состояние STARTED
- После того как фрагмент перейдет в состояние DESTROYED мы больше не сможем подписываться на ResultListener
Как это выглядит в коде?
Передача данных
Для передачи данных в другой фрагмент нам необходимо вызвать метод:
В параметры метода мы кладем ключ, который и будет нашим идентификатором для получения данных и сам Bundle. Этот Bundle будет содержать в себе передаваемые данные.
Получение данных
Для получения данных через FragmentManager мы регистрируем наш FragmentResultListener и задаем ключ по которому мы будем получать данные. Тот самый ключ который мы указывали в методе FragmentManager.setFragmentResult()
Здесь мы видим 2 аргумента: key: String и bundle: Bundle.
Первый — это тот самый ключ, по которому мы передаем сюда данные. Второй — Bundle, в котором лежат переданные данные.
Parent Fragment Manger
Выбор FragmentManager-а для передачи данных между фрагментами зависит от принимающего фрагмента:
- Если оба фрагмента находятся в одном и том же FragmentManager (например оба фрагмента находятся в Activity), то мы должны использовать родительский FragmentManager, который хранит в себе Activity
- Если у нас один фрагмент вложен в другой фрагмент, то для передачи данных мы используем childFragmentManager (он же родительский фрагмент для принимающего фрагмента)
Важно понимать, что наш FragmentResultListener должен находиться в общем для двух фрагментов FragmentManager-е.
Тестирование
Для тестирования отправки/получения данных через FragmentResultListener, мы можем использовать FragmentScenario API, который предоставляет нам все преимущества тестирования фрагментов в изоляции.
Передача данных
Как мы можем протестировать, что наш фрагмент корректно отправляет данные через родительский FragmentManager? Для этого нам необходимо внутри теста отправить результат и проверить, что наш FragmentResultListener получил корректные данные:
Получение данных
Для проверки корректности получения данных мы можем симулировать отправку данных, используя родительский FragmentManager. Если в отправляющем фрагменте корректно установлен FragmentResultListener мы должны получить корректные данные проверяя сам листенер или последствие их получения.
Вывод
В данный момент FragmentResultListener находится в альфе, а это значит что возможно еще будут изменения со стороны Google. Но уже сейчас видно, что это достаточно крутой инструмент, для передачи данных между фрагментами, не создавая дополнительных интерфейсов и классов. Единственным нюансом остается, пожалуй то, что не совсем понятно, как и где лучше хранить ключи где, но это не кажется таким уж большим минусом.
Для того чтоб получить возможность использовать FragmentResultListener нам нужно подключить в зависимостях версию фрагментов 1.3.0-alpha04 или новее:
Источник
Урок 15. Передача данных между экранами — пунктами назначения. Android Navigation. Bundle vs Safe Args
Продолжаем серию уроков по разработке android-приложений в Android Studio на языке Kotlin.
На прошлом уроке мы выполняли навигацию по условию, авторизован пользователь или нет.
На этом уроке
На этом уроке рассмотрим возможности передачи данных между экранами – пунктами назначения навигации в андроид-приложении. Создадим приложение с двумя экранами. На первом экране будет поле для ввода имени и кнопка отправки, а на втором экране будет отображаться приветствие с именем, которое мы указали. Таким образом, мы передадим данные (имя) с первого экрана на второй.
Передача данных между экранами
В процессе работы приложения часто возникает необходимость передавать данные между экранами. В уроке №5 мы рассматривали возможность передачи данных между активити с помощью интента. Для передачи данных между фрагментами такой способ не подходит, поскольку часто фрагменты отображаются в одном и том же активити.
Bundle или Safe Args?
В этом уроке мы рассмотрим два способа передачи данных между фрагментами: традиционный – с помощью наборов данных Bundle и типобезопасный – при помощи безопасных аргументов SafeArgs. Первый способ относительно прост – создаем набор данных «ключ-значение» типа Bundle и передаем через action в первом фрагменте, и извлекаем во втором фрагменте.
Второй способ потребует немного больше кода. На первый взгляд он может показаться сложнее, поскольку используется кодогенерация – среда разработки создает необходимые классы вместо вас. Но мы попробуем разобраться и вы увидите, что ничего особо сложного там нет. По сути, SafeArgs – просто обертка над Bundle. Тем не менее, разработчики настоятельно рекомендуют применять именно SafeArgs, как типобезопасный способ передачи данных между фрагментами в процессе навигации.
Создаем проект
Откройте среду разработки Android Studio и создайте новый проект с использованием шаблона Empty Activity.
Создаем граф навигации
Далее перейдите в папку res и создайте в ней папку navigation. Внутри папки navigation создайте Navigation Resource File с именем nav_graph.xml и корневым элементом .
Если вы забыли добавить в проект необходимые для поддержки навигации библиотеки – Android Studio предложит это сделать за вас, показав предупреждение.
Добавляем пункты назначения – фрагменты
Добавьте новые пункты назначения. Для этого:
- В окне редактора дизайна нажмите кнопку «New destination»
- Выберите «Create new destination»
- Далее в окне добавления фрагмента выберите Fragment (Blank):
Источник
Как в Android’е передать переменную из фрагмента в активность?
Рассказ о том, как в Android’е передать информацию из фрагмента (Fragment) в активность (Activity). Информация будет полезной для новичков (джуниоров), осваивающих программирование для Android, и вряд ли будет интересной для миддлов и сеньоров.
Запускаем IDE (integrated development environment) Android Studio. Создаём новый проект: File -> New -> New Project. Выбираем «Empty Activity», жмём «Next».
Заполняем поля «Name», «Package name», «Save location».
IDE автоматически создаст два файла: «MainActivity.java» — в каталоге «java/[имя пакета]», «activity_main.xml» — в каталоге «res/layout».
Java-файл определяет, что приложение делает, xml – как оно выглядит. Делает же оно пока совсем мало, только «setContentView(R.layout.activity_main);». Эта строка указывает приложению при запуске использовать макет «activity_main.xml». И, поскольку макет содержит только один виджет типа «TextView» с текстом «Hello World!», то и выглядит наше приложение тоже весьма скромно.
В папке проекта создадим фрагмент с именем «Fragment1».
IDE создаст два файла: «Fragment1» и «fragment_fragment1.xml».
Откроем файл макета фрагмента и удалим ненужный нам виджет «TextView» с приветственной строкой.
Переключимся в режим дизайна и перетащим на макет кнопку (Button).
IDE создаст кнопку с идентификатором «button1».
Теперь отредактируем макет главной активности, т.е. файл «activity_main.xml»
Переместим текстовый виджет повыше и добавим в макет созданный нами фрагмент (для этого нужно перетащить элемент «<>» на макет, выбрать «Fragment1» и кликнуть «OK»).
В макете активности в настройках фрагмента установим layout_height=«wrap_content» и отредактируем на свой вкус его размещение. Также изменим идентификатор текстового поля на «textReport», а фрагмента — на «fragmentWithButton».
Запустим эмулятор (Shift+F10) и посмотрим, что получилось.
Приложение отображает надпись «Hello World!» и кнопку «BUTTON». Надпись выводится из активности, кнопка же принадлежит фрагменту. Кнопка нажимается, но никакого эффекта это пока не даёт. Попробуем запрограммировать надпись отображать количество нажатий кнопки. Для этого нам нужно будет передать сообщение о нажатии кнопки из фрагмента в активность.
Вначале научим фрагмент подсчитывать число нажатий кнопки. Откроем файл «Fragment1.java».
Добавим переменную «counter». В методе «onCreateView», который вызывается сразу после создания фрагмента, создадим «слушатель» кнопки. IDE потребует имплементировать View.OnClickListener — соглашайтесь (Alt + Enter). Создадим (переопределим) метод onClick, который будет увеличивать значение переменной «counter» при каждом клике по кнопке и выводить всплывающее сообщение.
Проверим в эмуляторе (снова Shift+F10), как это работает. Нажатие кнопки приводит к появлению в нижней части экрана приложения всплывающего сообщения «Количество нажатий кнопки: … ».
Отлично, идём дальше. Наша главная цель — передать информацию (в данном случае — число нажатий кнопки) из экземпляра фрагмента в экземпляр активности. Увы, жизненные циклы активностей и фрагментов организованы так, что Android (почти) не позволяет активности и фрагменту общаться напрямую, поэтому нам понадобится посредник-интерфейс. Назовём его «Postman» (почтальон). Интерфейс можно создавать как в отдельном файле, так и в файле с кодом фрагмента; мы выберем первый вариант. Наш интерфейс Postman будет содержать единственный абстрактный (без «тела») метод «fragmentMail».
Переменную «numberOfClicks» мы будем использовать как «конверт» для передачи сообщений от фрагмента в активность.
Откроем файл с кодом активности «MainActivity.java». Как мы помним, он выглядит так:
Имплементируем интерфейс «Postman» и добавим в активность метод интерфейса «fragmentMail», переопределив его (Override).
Теперь, как только активность «увидит» в переменной «numberOfClicks» новое значение, она выведет обновлённое сообщение в текстовом поле «textReport».
Но нам ведь ещё нужно «положить письмо в конверт», т.е. передать в переменную количество кликов по кнопке. А это мы делаем в коде фрагмента. Открываем файл «Fragment1.java».
Д̶о̶б̶а̶в̶л̶я̶е̶м̶ ̶в̶ ̶п̶о̶д̶п̶и̶с̶ь̶ ̶к̶л̶а̶с̶с̶а̶ ̶и̶м̶п̶л̶е̶м̶е̶н̶т̶а̶ц̶и̶ю̶ ̶и̶н̶т̶е̶р̶ф̶е̶й̶с̶а̶ ̶«̶P̶o̶s̶t̶m̶a̶n̶»̶.̶ ̶I̶D̶E̶ ̶п̶о̶т̶р̶е̶б̶у̶е̶т̶ ̶п̶е̶р̶е̶о̶п̶р̶е̶д̶е̶л̶и̶т̶ь̶ ̶м̶е̶т̶о̶д̶ ̶и̶н̶т̶е̶р̶ф̶е̶й̶с̶а̶ ̶«̶f̶r̶a̶g̶m̶e̶n̶t̶M̶a̶i̶l̶»̶,̶ ̶н̶о̶ ̶д̶е̶л̶а̶т̶ь̶ ̶в̶ ̶н̶ё̶м̶ ̶м̶ы̶ ̶н̶и̶ч̶е̶г̶о̶ ̶н̶е̶ ̶б̶у̶д̶е̶м̶,̶ ̶п̶о̶э̶т̶о̶м̶у̶ ̶о̶с̶т̶а̶в̶и̶м̶ ̶е̶г̶о̶ ̶т̶е̶л̶о̶ ̶п̶у̶с̶т̶ы̶м̶. [Удалено, см. «Примечание 1 от 20.04.2019»]
Нам понадобится ссылка на экземпляр активности. Мы получим её при присоединении фрагмента к активности так:
В метод «onClick» (тот самый, который вызывается при нажатии кнопки нашего фрагмента) добавим обращение к интерфейсу из экземпляра активности.
Финальный код фрагмента после удаления (для компактности) комментариев выглядит так:
Теперь наш фрагмент считает количество нажатий кнопки, выводит их во всплывающем сообщении и затем с помощью интерфейса «Postman» передаёт значение переменной-счётчика в переменную numberOfClicks, служащую контейнером-конвертом для пересылки сообщения от фрагмента к активности. Активность, получая новое сообщение, тут же отображает его в своём текстовом поле-виджете с идентификатором «textReport». Цель достигнута!
Источник