- Доступ к View внутри фрагмента
- Доступ к View внутри динамического фрагмента из активности
- res/layout/fragmentlayout.xml
- Передача данных между фрагментами
- res/layout/redfragment.xml
- res/layout/bluefragment.xml
- Android Fragment Result Listener
- Как это работает?
- Как это выглядит в коде?
- Передача данных
- Получение данных
- Parent Fragment Manger
- Тестирование
- Передача данных
- Получение данных
- Вывод
- Котлин: передача данных во фрагмент
- 1 ответ
- Как в Android’е передать переменную из фрагмента в активность?
Доступ к View внутри фрагмента
Так как существует два способа использования фрагментов в активности, то взаимодействие между компонентами, которые находятся внутри фрагментов немного отличается.
Доступ к View внутри динамического фрагмента из активности
Рассмотрим пример доступа к компоненту, который находится внутри динамического фрагмента из активности.
Фрагмент может иметь собственную разметку и содержать различные компоненты View: TextView, EditText и т.д. Напрямую из активности обратиться к нужному компоненту и поменять, например, текст в TextView не получится. А как же достучаться до нужного компонента? Рассмотрим простой пример.
Создадим класс фрагмента MyFragment.java:
В методе onCreateView() мы указали ресурс разметки R.layout.fragmentlayout. Давайте создадим разметку для фрагмента.
res/layout/fragmentlayout.xml
В данной разметке нас интересует вторая текстовая метка с идентификатором fragmenttext.
Создадим разметку для основной активности:
Последняя компоновка LinearLayout с идентификатором myfragment является контейнером для фрагмента, который будет его замещать. Напишем код для главной активности:
При запуске программы мы получаем экземпляр класса FragmentTransaction и добавляем фрагмент на экран вместо LinearLayout. Теперь текстовая метка фрагмента доступна для изменения — получаем ссылку на нужный компонент и устанавливаем требуемый текст.
Передача данных между фрагментами
Когда мы заменяем контейнер своим фрагментом, то он становится частью активности и получаем доступ к компонентам стандартным способом, как в примере выше. Если мы используем фрагменты как самостоятельные элементы, то доступ к компонентам происходит немного по-другому. Так как фрагменты не существуют сами по себе, а только внутри активности, то сначала нужно получить доступ к родительской активности через метод getActivity(), а затем уже можно получить доступ к нужному компоненту из фрагмента:
Создадим разметки для двух фрагментов. В одном разместим текстовое поле, а во втором кнопку и текстовую метку, в которой будем выводить текст из текстового поля первого фрагмента:
res/layout/redfragment.xml
res/layout/bluefragment.xml
В код первого фрагмента добавим только наполнение из разметки:
В класс второго фрагмента добавим код для чтения данных из первого фрагмента. Сделаем это в методе onStart():
Мы получаем ссылки на все компоненты и обрабатываем щелчок мыши. В разметку активности добавьте два созданных фрагмента и запустите пример. Введите какой-нибудь текст в текстовом поле (напоминаю, что он относится к первому фрагменту). Нажмите на кнопку, которая относится ко второму фрагменту. В текстовой метке второго фрагмента появится введённым вами текст.
Источник
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 или новее:
Источник
Котлин: передача данных во фрагмент
У меня есть фрагмент, содержащий RecyclerView. С помощью этого RecyclerView я хочу щелкнуть любое из представлений, чтобы открыть другой фрагмент (который содержит другое представление переработчика). Каждое представление RecyclerView содержит URL-адрес изображения и некоторый текст. Я хочу, чтобы оба из них были переданы второму фрагменту, чтобы я мог использовать его в ImageView и TextView.
Мне удалось открыть второй фрагмент с помощью адаптера RecyclerView, но мне трудно передать данные из RecyclerView во второй фрагмент.
Адаптер RecyclerView
Фрагмент, на который я пытаюсь отправить информацию
После нажатия на представление из RecyclerView оператор журнала в моем классе адаптера показывает, что правильная строка помещается в конструктор newInstance. Однако во втором фрагменте мой оператор журнала для индекса показывает, что он равен нулю.
1 ответ
Хорошо, мне удалось выяснить, как получить данные во второй фрагмент. Решение, которое я нашел, не было слишком сложным, поэтому я думаю, что это поможет кому-то, кто просто пришел в кодирование / котлин, как и я. Возможно, это не самый эффективный способ, но для меня он достаточно хорош.
По сути, я добавил интерфейс и прослушиватель для передачи информации от щелчка по recyclerview до фрагмента №1, который содержит recyclerview, до фрагмента №2. Я сообщил три части данных: позицию в списке и две строки (одна из которых является URL-адресом изображения).
Два источника, которые я использовал для разработки кода, — это видео, в котором рассказывается, как получить данные через onClickListener из RecyclerView в мой фрагмент № 1 (MainFragment) и руководство, в котором показано, как передать эти данные во фрагмент № 2 (CarListFragment).
Сначала я создал интерфейс: Я поместил это в отдельный файл, чтобы все было немного аккуратнее
В моем адаптере RecyclerView:
- удалил OnClickListener из моего onBindViewHolder, поскольку это замедляет работу приложения (это то, что я изначально делал в вопросе)
- добавлен private val listener: Communicator в конструктор адаптера вверху
- в моем классе ViewHolder
- изменил класс на внутренний класс
- добавил View.OnClickListener после расширяет «:»
- добавлен блок инициализации для setOnClickListener
- добавил override fun onClick(v: View?)
Шаги для этого были выполнены из видео, которое я связал.
В моем фрагменте №1 (который содержит RecyclerView):
- реализовать Коммуникатор во фрагменте, добавив его после «:»
- добавлен контекст для слушателя в адаптере line adapter = ManuAdapter(it, this@MainFragment)
- добавлена функция passData внутри класса фрагмента №1.
Все, вплоть до создания функции onItemClick, описано в видео, отсюда я до конца следовал руководству.
Во фрагменте №2
- добавил три переменные после инициализации фрагмента
- взял переменные из интерфейса коммуникатора
Manu_pic и manu_name — это просто идентификаторы ImageView и TextView в XML, увеличенные фрагментом.
Надеюсь, кто-то сочтет эту информацию полезной.
Источник
Как в 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». Цель достигнута!
Источник