Как из фрагмента передать данные в активити

от admin

Передача данных из фрагмента в Activity

Подскажите, как сделать так, чтобы при нажатии на пункт списка, в TextView устанавливался какой-либо текст? Например, если выбран adapter1 , осуществляется переход в Activity и в TextView указывается текст: «Выбран адаптер 1». Если выбран adapter2 , то вместе с переходом текст меняется на «Выбран адаптер 2».

Спасибо за помощь.

Тут уже советовали не очень красивое решение в виде ((Info) getActivity()).имя_метода(); .

Но такое лучше делать интерфейсами.

Теперь, если вам надо отправить данные в Activity из вашего фрагмента, вызывайте:

Как в 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». Цель достигнута!

Communicate between fragments and activity using LiveData

We will first look at the primitive ways of doing these and what certainly is not good in these ways. Moving forward we will see the new and optimized way to handle these communications using ViewModel and LiveData.

I. Communication between fragments

Earlier to communicate between fragments, we had to pass data from one fragment to parent activity and then from this parent activity to another fragment using interface callbacks. This was the only effective way to handle communication since activity has the context and child fragments uses that context to sync along the life cycle.

Читать:
Компас операция без истории 3д как восстановить историю

Let’s consider an example where we want to pass data from WallFragment to WallDetailFragment using interface callbacks. The first step is to create an interface(some call it a contract) with an abstract function handleOnClick.

Next step is to attach the parent activity to this listener and then we can call handleOnClick on this fragmentListener to pass flow to the activity which has implemented that interface/contract.

From MainActivity we then call the function of another Fragment to pass data to it.

Pain Points in this primitive way:

  1. Using interface callbacks ends up being more work to implement and it is not easily reusable in other Fragments.
  2. Both fragments need to create the interface if communication is in both ways(I think this is totally redundant!)
  3. Explicitly we need to take care of both fragments’ life cycle synchronization with parent activity since the parent activity is binding the two fragments.

Here comes the LiveData to rescue!

With the release of architecture components, we can handle all these pain points by creating a Shared ViewModel and expose the data stream using LiveData. (Read more about ViewModel and LiveData)

This is our extended ViewModel, SharedViewModel class.

Now, in our fragments, we will start observing for the changes in the data by calling the ViewModel with the same activity scope.

That’s it! We just got rid of too much of boilerplate code, issue of coupling, and yes ViewModel takes care of the lifecycle and observes data when needed.

II. Communication between activity and fragment

The same primitive way of interface callbacks also applies here. However, the pain points can be avoided here if you keep the advantages of ViewModel aside. You can pretty fairly achieve a good efficient structure with interface callbacks since here you just need to communicate between an activity and its child fragment.
But the recommended way to achieve this type of communication is still using LiveData and ViewModel due to their advantages including lifecycle awareness and reduced boilerplate code.

You just need to observe the Live Data on the View Model and you are good to go!

Major Advantage

We can use the same ViewModel at multiple places to observe the changes made anywhere inside the application. Also, we can observe the emitted data via LiveData at all places which are observing for the data update. This is a n is to m relationship.

Доступ к 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():

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

Похожие статьи