Android send data to fragment from activity

Полный список

— рассмотрим взаимодействие между Activity и ее фрагментами

После размещения фрагмента, хотелось бы начать с ним взаимодействовать. Т.е. размещать View-компоненты и работать с ними, обращаться к фрагментам из Activity и наоборот. Попробуем это реализовать.

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

Project name: P1061_FragmentActivity
Build Target: Android 4.1
Application name: FragmentActivity
Package name: ru.startandroid.develop.p1061fragmentactivity
Create Activity: MainActivity

В strings.xml добавим строки:

Создаем layout и классы для двух фрагментов.

У фрагмента нет привычного для нас метода findViewById для поиска компонентов с экрана. Поэтому вызываем этот метод для View, которое будет содержимым фрагмента. В методе onCreateView мы создаем View и сразу же находим в нем кнопку и ставим ей обработчик. Затем отдаем View системе.

Все аналогично Fragment1.

Настраиваем основное Activity.

Кнопка, компонент fragment, в который помещен Fragment1, и контейнер FrameLayout, в который потом поместим Fragment2.

Обратите внимание на атрибут tools:layout. В нем указан layout-файл, и мы можем на этапе разработки видеть, как будет выглядеть статический фрагмент, когда приложение будет запущено.

Для этого надо нажать правой кнопкой на компоненте fragment, и через пункт Fragment Layout указать нужный layout.

Здесь мы просто добавляем Fragment2 в контейнер.

Все сохраняем, запускаем приложение.

Жмем кнопку Log в первом фрагменте и смотрим лог:

Button click in Fragment1

Жмем Log во втором фрагменте:

Button click in Fragment2

Все ок. Компоненты в фрагментах нашлись и обработчики среагировали на нажатия.

Атрибут onClick, который мы привыкли использовать для кнопки, здесь не прокатит. Указанный в этом атрибуте метод, будет вызван в Activity, а не в фрагменте.

Доступ к фрагменту из Activity

Разберемся, как получить доступ к фрагменту из Activity. Для этого у FragmentManager есть метод findFragmentById, который на вход принимает id компонента fragment (если фрагмент статический) или id контейнера (если динамический).

У нас в main.xml есть кнопка btnFind, вызывающая метод onClick при нажатии. Дорисуем в MainActivity.java метод onClick:

Используем метод findFragmentById. В первом случае на вход передаем id компонента fragment, т.к. Fragment1 у нас размещен именно так. При поиске Fragment2 указываем id контейнера, в который этот фрагмент был помещен. В результате метод findFragmentById возвращает нам объект Fragment.

Далее мы получаем доступ к его View с помощью метода getView, находим в нем TextView и меняем текст.

Все сохраняем, запускаем. Жмем кнопку Find

Тексты в фрагментах обновились. Тем самым из Activity мы достучались до фрагментов и их компонентов.

На всякий случай проговорю одну вещь из разряда «Спасибо кэп!». Если посмотреть на код MainActivity, то можно заметить, что работая с frag2 в методе onCreate и с frag2 в методе onClick мы работаем с текущим фрагментом Fragment2. Это так и есть. Оба frag2 в итоге будут ссылаться на один объект. Так что, если вы динамически добавили фрагмент, то у вас уже есть ссылка на него, и искать его через findFragmentById вам уже не надо.

Доступ к Activity из фрагмента

Теперь попробуем из фрагмента поработать с Activity. Для этого фрагмент имеет метод getActivity.

Давайте перепишем обработчик кнопки в первом фрагменте. Будем менять текст кнопки btnFind.

Получаем Activity методом getActivity, ищем в нем кнопку и меняем текст.

Сохраняем, запускаем. Жмем кнопку в первом фрагменте:

Работает. Из фрагмента мы поменяли компонент Activity.

Обработка в Activity события из фрагмента

Рассмотрим механизм, который описан в хелпе: фрагмент генерирует некое событие и ставит Activity обработчиком.

Например, в Activity есть два фрагмента. Первый – список заголовков статей. Второй – отображает содержимое статьи, выбранной в первом. Мы нажимаем на заголовок статьи в первом фрагменте и получаем содержимое во втором. В этом случае, цель первого фрагмента – передать в Activity информацию о том, что выбран заголовок. А Activity дальше уже сама решает, что делать с этой информацией. Если, например, приложение запущено на планшете в горизонтальной ориентации, то можно отобразить содержимое статьи во втором фрагменте. Если же приложение запущено на смартфоне, то экран маловат для двух фрагментов и надо запускать отдельное Activity со вторым фрагментом, чтобы отобразить статью.

Фишка тут в том, что первому фрагменту неинтересны все эти терзания Activity. Фрагмент – обособленный модуль. Его дело — проинформировать, что выбрана статья такая-то. Ему не надо искать второй фрагмент и работать с ним – это дело Activity.

Читайте также:  Название элементов экрана android

Тут немного отвлекусь на небольшое лирическое отступление. Модульность, вообще, — очень важная и полезная штука. И ее надо использовать для универсальности, удобности и легкости в понимании работы своих приложений. Но уникальных рецептов, как правильно все организовать, конечно, нет. Каждый делает по-своему. Именно по этим причинам я в своих уроках даю чисто технические вещи про отдельные компоненты и не рассказываю, как организовывать и писать целое приложение. Иначе, форум бы уже ломился от сообщений, что я все делаю не так и надо по-другому, и каждый бы излагал свое видение. И была бы куча споров, где одна сторона говорит, что крокодил зеленый, а другая сторона говорит, что он нифига не зеленый, а длинный ))

Вернемся к уроку. Фрагмент должен сообщить в Activity, что выбрана статья. Для этого он будет вызывать некий метод в Activity. И как нам сообщает хелп, лучший способ тут – это использовать интерфейс, который мы опишем в фрагменте и который затем будет реализован в Activity. Схема известная и распространенная. Давайте реализуем. В нашем приложении никаких статей нет, поэтому будем просто передавать произвольную строку из второго фрагмента в Activity. А Activity уже будет отображать эту строку в первом фрагменте.

Описываем интерфейс onSomeEventListener. В нем метод someEvent, который на вход получает строку. Этот интерфейс будет реализовывать Activity.

В методе onAttach мы на вход получаем Activity, к которому присоединен фрагмент. Мы пытаемся привести это Activity к типу интерфейса onSomeEventListener, чтобы можно было вызывать метод someEvent и передать туда строку. Теперь someEventListener ссылается на Activity.

Далее, в onCreateView, в обработчике кнопки мы вызываем метод someEvent и передаем туда текст. Этот метод будет отработан в Activity.

Теперь меняем Activity.

Дописываем интерфейс onSomeEventListener к описанию класса.

onCreate без изменений.

Реализуем метод someEvent. Просто ищем первый фрагмент и вставляем туда текст.

Все сохраняем и запускаем. Жмем кнопку во втором фрагменте:

Второй фрагмент передал через интерфейс строку в Activity, а оно нашло первый фрагмент и отобразило там эту строку.

На следующем уроке:

— размещаем элементы в ActionBar

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

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 или новее:

Источник

Отправить данные из активности на фрагмент в Android

У меня есть два класса. Во-первых, это деятельность, во-вторых, фрагмент, где у меня есть некоторые EditText . В действии у меня есть подкласс с асинхронной задачей, и в методе doInBackground я получаю некоторый результат, который я сохраняю в переменную. Как я могу отправить эту переменную из подкласса «моя деятельность» в этот фрагмент?

Из Activity вы отправляете данные с намерением:

и в методе Fragment onCreateView:

Также Вы можете получить доступ к данным активности из фрагмента:

Деятельность:

Фрагмент:

Я нашел много ответов здесь @ stackoverflow.com, но определенно это правильный ответ:

«Отправка данных от активности к фрагменту в Android».

Деятельность:

Фрагмент:

Чтение значения во фрагменте

Этот ответ может быть слишком поздно. но это будет полезно для будущих читателей.

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

Шаг 1: Создайте интерфейс в Основном действии.

Шаг 2. Создайте ссылку SelectedBundle для той же операции

Шаг 3: создайте метод в той же операции

Шаг 4: Необходимо инициализировать ссылку SelectedBundle, для которой все фрагменты нуждаются в функции выбора файлов. Вы помещаете этот код в onCreateView(..) метод фрагмента

Шаг 5: моем случае мне нужно передать изображение Uri из HomeActivity во фрагмент. Итак, я использовал эту функциональность в методе onActivityResult.

onActivityResult из MainActivity, передайте значения фрагментам, используя интерфейс.

Примечание: ваш случай может быть другим. Вы можете позвонить из любого места из вашей HomeActivity.

Вот и все. Реализуйте каждый фрагмент, который вам нужен, в FragmentClass. Ты замечательный. ты сделал. ВОТ ЭТО ДА.

Основная идея использования Fragments (F) заключается в создании многократно используемых самодостаточных компонентов пользовательского интерфейса в приложениях для Android. Эти фрагменты содержатся в действиях, и существует распространенный (лучший) способ создания путей связи из A -> F и FA. Необходимо обмениваться информацией между FF через действие, потому что тогда только фрагменты становятся разъединенными и самодостаточными.

Таким образом, передача данных из A -> F будет такой же, как объяснено ρяσѕρєя K. В дополнение к этому ответу, после создания фрагментов внутри Activity, мы также можем передавать данные фрагментам, вызывающим методы во Fragments.

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

Например: если ваш фрагмент называется MyFragment

так что вы будете называть свой фрагмент из активности следующим образом:

* R.id.container — это идентификатор моего FrameLayout

поэтому в MyFragment.newInstance («data1», «data2») вы можете отправлять данные во фрагмент, а в своем фрагменте вы получаете эти данные в MyFragment newInstance (String param1, String param2)

Читайте также:  Google play для андроид тв приставки

а затем в методе фрагмента onCreate вы получите данные:

так что теперь у mParam1 есть данные1, а у mParam2 есть данные2

Теперь вы можете использовать эти mParam1 и mParam2 в своем фрагменте.

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

Если вы используете фрагмент в классе java, где у вас есть данные, которые вы хотите передать, вы можете применить первый ответ для передачи данных:

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

Это не будет работать, даже если вы замените PlaceholderFragment по умолчанию на FragmentClasses, и даже если вы исправите FragmentPagerAdapter в новой ситуации, добавив переключатель для getItem () и другой переключатель для getPageTitle () (как показано здесь) )

Предупреждение: упомянутый выше клип содержит ошибки кода, которые я объясню позже, но полезно посмотреть, как вы переходите от кода по умолчанию к редактируемому коду для фрагментов с вкладками)! Остальная часть моего ответа имеет гораздо больше смысла, если вы рассмотрите java-классы и xml-файлы из этого клипа (представитель для первого использования фрагментов с вкладками в сценарии новичка).

Основная причина, по которой наиболее одобренный ответ на этой странице не сработает, заключается в том, что в этом коде по умолчанию для фрагментов с вкладками фрагменты используются в другом классе Java: FragmentPagerAdapter!

Таким образом, для отправки данных у вас возникает желание создать пакет в MotherActivity и передать его в FragmentPagerAdapter, используя ответ № 2.

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

Я думаю, что правильный / более простой способ сделать это — передать данные непосредственно в рассматриваемый фрагмент, используя ответ № 2. Да, между фрагментами с вкладками будет тесная связь между заданием и фрагментом, но это своего рода ожидание. Я бы даже посоветовал вам создать фрагменты с вкладками внутри Java-класса MotherActivity (в виде подклассов, так как они никогда не будут использоваться вне MotherActivity) — это просто, просто добавьте в Java-класс MotherActivity столько фрагментов, сколько вам нужно, вот так:

Таким образом, чтобы передать данные из MotherActivity в такой фрагмент, вам нужно создать частные строки / связки выше onCreate вашей материнской активности, которые вы можете заполнить данными, которые хотите передать во фрагменты, и передать их через метод, созданный после onCreate (здесь он называется getMyData ()).

И затем в классе фрагмента вы используете getMyData:

Если у вас есть запросы к базе данных, я советую вам делать их в MotherActivity (и передавать их результаты в виде строк / целых чисел, прикрепленных к ключам внутри пакета, как показано выше), так как внутри фрагментов с вкладками ваш синтаксис станет более сложным (это становится getActivity (), например, и getIntent становится getActivity (). getIntent), но у вас также есть возможность сделать то, что вы хотите.

Мой совет для начинающих — сосредоточиться на маленьких шагах. Во-первых, получите намерение открыть очень простое действие с вкладками без передачи ЛЮБЫХ данных. Это работает? Открывает ли он ожидаемые вами вкладки? Если нет, то почему?

Начните с этого, и, применяя решения, подобные представленным в этом ролике , посмотрите, чего не хватает. Для этого конкретного клипа файл mainactivity.xml никогда не отображается. Это, безусловно, смущает вас. Но если вы обратите внимание, вы увидите, что, например, контекст (tools: context) неверен в файлах фрагментов xml. Каждый фрагмент XML должен указывать на правильный класс фрагмента (или подкласс, используя разделитель $).

Вы также увидите, что в основной Java-класс активности вам нужно добавить tabLayout.setupWithViewPager (mViewPager) — сразу после строки TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); без этой строки ваше представление на самом деле не связано с XML-файлами фрагментов, но показывает ТОЛЬКО XML-файл основного действия.

В дополнение к строке в Java-классе основного действия в XML-файле основного действия необходимо изменить вкладки в соответствии с вашей ситуацией (например, добавить или удалить TabItems). Если у вас нет вкладок в основном XML-задании, возможно, вы не выбрали правильный тип действия при первом его создании (новое действие — действие с вкладками).

Обратите внимание, что в последних 3 абзацах я говорю о видео! Поэтому, когда я говорю «основное действие XML», это основное действие XML в видео, которое в вашей ситуации является XML-файлом MotherActivity.

Источник

Оцените статью